barra de rolagem horizontal na parte superior e inferior da tabela

159

Eu tenho um muito grande tablena minha página. Então, decidi colocar uma barra de rolagem horizontal na parte inferior da mesa. Mas eu gostaria que essa barra de rolagem também estivesse em cima da mesa.

O que tenho no modelo é o seguinte:

<div style="overflow:auto; width:100%; height:130%">
<table id="data" style="width:100%">...</table>
</div>

Isso é possível apenas em HTML e CSS?

psoares
fonte
1
stackoverflow.com/questions/2274627/… Encontrei esta solução útil.
varsha DAS

Respostas:

234

Para simular uma segunda barra de rolagem horizontal na parte superior de um elemento, coloque um "manequim" divacima do elemento que possui rolagem horizontal, alta o suficiente para uma barra de rolagem. Em seguida, anexe manipuladores do evento "scroll" para o elemento dummy e o elemento real, para sincronizar o outro elemento quando qualquer barra de rolagem for movida. O elemento fictício parecerá uma segunda barra de rolagem horizontal acima do elemento real.

Para um exemplo ao vivo , veja este violino

Aqui está o código :

HTML:

<div class="wrapper1">
  <div class="div1"></div>
</div>
<div class="wrapper2">
  <div class="div2">
    <!-- Content Here -->
  </div>
</div>

CSS:

.wrapper1, .wrapper2 {
  width: 300px;
  overflow-x: scroll;
  overflow-y:hidden;
}

.wrapper1 {height: 20px; }
.wrapper2 {height: 200px; }

.div1 {
  width:1000px;
  height: 20px;
}

.div2 {
  width:1000px;
  height: 200px;
  background-color: #88FF88;
  overflow: auto;
}

JS:

$(function(){
  $(".wrapper1").scroll(function(){
    $(".wrapper2").scrollLeft($(".wrapper1").scrollLeft());
  });
  $(".wrapper2").scroll(function(){
    $(".wrapper1").scrollLeft($(".wrapper2").scrollLeft());
  });
});
StanleyH
fonte
resposta realmente ótima! Muito obrigado! :) então tentei usar o seu exemplo, mas a barra na parte superior não funciona e, quando tentei aumentar a largura, a barra de rolagem desapareceu. alguma idéia do porquê?
Psoares
1
Conseguiu fazê-lo funcionar? Para obter mais informações sobre o jQuery, consulte api.jquery.com/scrollLeft (é claro, você pode fazê-lo sem o jQuery anexando diretamente os manipuladores do onscroll.) .
StanleyH
1
sim, consegui que funcionasse, apenas adicionei <script type = "text / javascript" src = "path"> </script> ao <head>. Então, toda vez que adiciono o jquery, era necessário adicionar o que o @fudgey adiciona? Desculpe, javascript e jQuery ainda são uma espécie de chinese para mim
psoares
4
@ StanleyH: como definir a div para assumir automaticamente a largura da tabela dentro dela? Eu não quero especificar a largura do div2 manualmente, mas quero que ele aceite automaticamente a largura da tabela que contém.
Sqlchild 12/05
3
@CodyGuldner: como definir a div para assumir automaticamente a largura da tabela dentro dela? Eu não quero especificar a largura do div2 manualmente, mas quero que ele aceite automaticamente a largura da tabela que contém.
Sqlchild
38

Tente usar o jquery.doubleScrollplugin :

jQuery:

$(document).ready(function(){
  $('#double-scroll').doubleScroll();
});

CSS:

#double-scroll{
  width: 400px;
}

HTML:

<div id="double-scroll">
  <table id="very-wide-element">
    <tbody>
      <tr>
        <td></td>
      </tr>
    </tbody>
  </table>
</div>
pawel.suwala
fonte
5
Consulte github.com/avianey/jqDoubleScroll para obter uma versão do incrível plug-in de Pawel que não requer jQueryUI.
fatal_error
1
O link leva a um GitHub não mantido com links quebrados em leia-me. Ainda não tentei o js real.
Paul Gorbas
19

Primeiro de tudo, ótima resposta, @ StanleyH. Se alguém estiver se perguntando como criar o contêiner de rolagem dupla com largura dinâmica:

css

.wrapper1, .wrapper2 { width: 100%; overflow-x: scroll; overflow-y: hidden; }
.wrapper1 { height: 20px; }
.div1 { height: 20px; }
.div2 { overflow: none; }

js

$(function () {
    $('.wrapper1').on('scroll', function (e) {
        $('.wrapper2').scrollLeft($('.wrapper1').scrollLeft());
    }); 
    $('.wrapper2').on('scroll', function (e) {
        $('.wrapper1').scrollLeft($('.wrapper2').scrollLeft());
    });
});
$(window).on('load', function (e) {
    $('.div1').width($('table').width());
    $('.div2').width($('table').width());
});

html

<div class="wrapper1">
    <div class="div1"></div>
</div>
<div class="wrapper2">
    <div class="div2">
        <table>
            <tbody>
                <tr>
                    <td>table cell</td>
                    <td>table cell</td>
                    <!-- ... -->
                    <td>table cell</td>
                    <td>table cell</td>
                </tr>
            </tbody>
        </table>
    </div>
</div>

demonstração

http://jsfiddle.net/simo/67xSL/

simo
fonte
3
Use $('.div1').width( $('.div1')[0].scrollWidth)para obter a largura real de rolagem do conteúdo, útil quando você não estiver usando especificamente um contêiner como uma tabela. @simo companheiro de esforço impressionante.
Clain Dsilva
Para esclarecer, também precisei alterar o código para scrollWidth para que meu próprio código funcionasse onde a largura do conteúdo na div "div2" era variável devido ao conteúdo dinâmico do servidor localizado lá.
AdamJones
15

Sem JQuery (2017)

Como você pode não precisar do JQuery, eis uma versão funcional do Vanilla JS com base na resposta @StanleyH:

var wrapper1 = document.getElementById('wrapper1');
var wrapper2 = document.getElementById('wrapper2');
wrapper1.onscroll = function() {
  wrapper2.scrollLeft = wrapper1.scrollLeft;
};
wrapper2.onscroll = function() {
  wrapper1.scrollLeft = wrapper2.scrollLeft;
};
#wrapper1, #wrapper2{width: 300px; border: none 0px RED;
overflow-x: scroll; overflow-y:hidden;}
#wrapper1{height: 20px; }
#wrapper2{height: 100px; }
#div1 {width:1000px; height: 20px; }
#div2 {width:1000px; height: 100px; background-color: #88FF88;
overflow: auto;}
<div id="wrapper1">
    <div id="div1">
    </div>
</div>
<div id="wrapper2">
    <div id="div2">
    aaaa bbbb cccc dddd aaaa bbbb cccc 
    dddd aaaa bbbb cccc dddd aaaa bbbb 
    cccc dddd aaaa bbbb cccc dddd aaaa 
    bbbb cccc dddd aaaa bbbb cccc dddd
    </div>
</div>

rap-2-h
fonte
este realmente não é sensível / dinâmico no caso que você não sabe a sua largura
prata elad
sim! tem as mesmas advertências que a resposta original por @StanleyH
rap-2-h
11

Você pode usar um plugin jQuery que fará o trabalho para você:

O plugin irá lidar com toda a lógica para você.

avianey
fonte
2
Embora este plug-in faça a mesma coisa que o plug-in suwala / jquery.doubleScroll, ele tem mais opções como recalcular a largura na janela
Tamanho
1
Também não depende da interface do usuário do jquery.
tribe84
1
Eu recomendaria este plugin, parece uma versão aprimorada do suwala / jquery.doubleScroll e funciona para mim
Russell England
Primeiro obrigado pelo ótimo plugin! No entanto, tenho um problema com a direção da rolagem: rtl. Parece que não o suporta corretamente. Se algum de vocês gurus do javascripts sabe como consertá-lo aqui, é o violino: jsfiddle.net/qsn7tupc/3 Observe que ele funciona no Chrome, mas em nenhum outro navegador.
Vlado
10

A resposta de StanleyH foi excelente, mas teve um erro infeliz: clicar na área sombreada da barra de rolagem não salta mais para a seleção em que você clica. Em vez disso, o que você obtém é um incremento muito pequeno e um tanto irritante na posição da barra de rolagem.

Testado: 4 versões do Firefox (100% afetado), 4 versões do Chrome (50% afetadas).

Aqui está meu violão . Você pode contornar isso com uma var on / off (true / false) que permite que apenas um evento onScroll () seja acionado por vez:

var scrolling = false;
$(".wrapper1").scroll(function(){
    if(scrolling) {
      scrolling = false;
      return true;
    }
    scrolling = true;
    $(".wrapper2")
        .scrollLeft($(".wrapper1").scrollLeft());
});
$(".wrapper2").scroll(function(){
    if(scrolling) {
      scrolling = false;
      return true;
    }
      scrolling = true;
    $(".wrapper1")
        .scrollLeft($(".wrapper2").scrollLeft());
});

Comportamento do problema com resposta aceita:

Comportamento realmente desejado:

Então, por que isso acontece? Se você executar o código, verá que wrapper1 chama scrollLeft de wrapper2 e wrapper2 chama scrollLeft de wrapper1 e repete isso infinitamente, portanto, temos um problema de loop infinito. Ou melhor: a rolagem contínua do usuário entra em conflito com a chamada de rolagem do wrapperx, ocorre um conflito de eventos e o resultado final é não pular nas barras de rolagem.

Espero que isso ajude alguém!

HoldOffHunger
fonte
ótima explicação! na verdade, estava fazendo um loop infinito
Ahmed Aboud
Sim. Muito obrigado pelo seu apoio! É útil para mim.
Giang D.MAI
3

Vincular os scrollers funcionou, mas da maneira como está escrito, ele cria um loop que torna a rolagem lenta na maioria dos navegadores se você clicar na parte da barra de rolagem mais clara e segurá-la (não ao arrastar o scroller).

Eu o consertei com uma bandeira:

$(function() {
    x = 1;
    $(".wrapper1").scroll(function() {
        if (x == 1) {
            x = 0;
            $(".wrapper2")
                .scrollLeft($(".wrapper1").scrollLeft());
        } else {
            x = 1;
        }
    });


    $(".wrapper2").scroll(function() {
        if (x == 1) {
            x = 0;
            $(".wrapper1")
                .scrollLeft($(".wrapper2").scrollLeft());
        } else {
            x = 1;
        }
    });
});
Yossi Vainshtein
fonte
Isso resolve um problema que eu estava tendo com as respostas sugeridas aqui também. No entanto, isso apenas atenua um pouco o problema; ainda pode haver rolagem lenta / lenta se a distância que você deseja rolar for grande o suficiente para isso.
Dan Temple
Com o sinalizador / condicional, essa solução funciona bem e os testes correspondem ao comportamento que você esperaria sem que o JavaScript fosse aplicado no navegador.
userabuser
3

uma solução apenas em javascript, baseada nas respostas @HoldOffHunger e @bobince

<div id="doublescroll">

.

function DoubleScroll(element) {
            var scrollbar= document.createElement('div');
            scrollbar.appendChild(document.createElement('div'));
            scrollbar.style.overflow= 'auto';
            scrollbar.style.overflowY= 'hidden';
            scrollbar.firstChild.style.width= element.scrollWidth+'px';
            scrollbar.firstChild.style.paddingTop= '1px';
            scrollbar.firstChild.appendChild(document.createTextNode('\xA0'));
            var running = false;
            scrollbar.onscroll= function() {
                if(running) {
                    running = false;
                    return;
                }
                running = true;
                element.scrollLeft= scrollbar.scrollLeft;
            };
            element.onscroll= function() {
                if(running) {
                    running = false;
                    return;
                }
                running = true;
                scrollbar.scrollLeft= element.scrollLeft;
            };
            element.parentNode.insertBefore(scrollbar, element);
        }

    DoubleScroll(document.getElementById('doublescroll'));
Ahmed Aboud
fonte
3

Baseado na solução @StanleyH, criei uma diretiva AngularJS , demo no jsFiddle .

Fácil de usar:

<div data-double-scroll-bar-horizontal> {{content}} or static content </div>

Para desenvolvedores do AngularJS

przno
fonte
31
"Não é necessário jQuery." Sim, apenas uma estrutura inteira. Nada demais.
PitaJ
2

Tanto quanto sei, isso não é possível com HTML e CSS.

punkrockbuddyholly
fonte
bem este é realmente o que eu pensava .. Mas eu gostaria de sabe se alguém fez isso, ea melhor maneira de fazer isso ..
psoares
Para HTML e CSS, não há melhor maneira. Simplesmente, não é possível. Você precisa usar outras técnicas, como javascript, para obter esse tipo de funcionalidade.
23610 Justus Romijn
1
você pode dar algumas dicas para começar a procurar?
Psoares
2
Isso não fornece uma resposta para a pergunta. Para criticar ou solicitar esclarecimentos a um autor, deixe um comentário abaixo da postagem.
SSA
2
@SSA responde à pergunta. A pergunta era "Isso é possível fazer apenas em HTML e CSS?" e a resposta para isso é "não".
precisa saber é o seguinte
2

Na baunilha Javascript / Angular, você pode fazer o seguinte:

scroll() {
    let scroller = document.querySelector('.above-scroller');
    let table = document.querySelector('.table');
    table.scrollTo(scroller.scrollLeft,0);
  }

HTML:

<div class="above-scroller" (scroll)="scroll()">
  <div class="scroller"></div>
</div>
<div class="table" >
  <table></table>
</div>

CSS:

.above-scroller  {
   overflow-x: scroll;
   overflow-y:hidden;
   height: 20px;
   width: 1200px
 }

.scroller {
  width:4500px;
  height: 20px;
}

.table {
  width:100%;
  height: 100%;
  overflow: auto;
}
Jakub Bares
fonte
1

Expandindo a resposta de StanleyH e tentando encontrar o mínimo necessário, eis o que eu implementei:

JavaScript (chamado uma vez de algum lugar como $(document).ready()):

function doubleScroll(){
        $(".topScrollVisible").scroll(function(){
            $(".tableWrapper")
                .scrollLeft($(".topScrollVisible").scrollLeft());
        });
        $(".tableWrapper").scroll(function(){
            $(".topScrollVisible")
                .scrollLeft($(".tableWrapper").scrollLeft());
        });
}

HTML (observe que as larguras mudarão o comprimento da barra de rolagem):

<div class="topScrollVisible" style="overflow-x:scroll">
    <div class="topScrollTableLength" style="width:1520px; height:20px">
    </div>
</div>
<div class="tableWrapper" style="overflow:auto; height:100%;">
    <table id="myTable" style="width:1470px" class="myTableClass">
...
    </table>

É isso aí.

MattC
fonte
1

para todos os fãs angulares / nativos, implementando a resposta do @ simo

HTML (sem alteração)

<div class="top-scroll-wrapper">
    <div class="top-scroll"></div>
</div>

CSS (sem alteração, largura: 90% é meu desejo)

.top-scroll-wrapper { width: 90%;height: 20px;margin: auto;padding: 0 16px;overflow-x: auto;overflow-y: hidden;}
.top-scroll { height: 20px; }

JS (como onload) ou ngAfterViewChecked(todos assão para TypeScript)

let $topscroll = document.querySelector(".top-scroll") as HTMLElement
let $topscrollWrapper = document.querySelector(".top-scroll-wrapper") as HTMLElement
let $table = document.querySelectorAll('mat-card')[3] as HTMLElement

$topscroll.style.width = totalWidth + 'px'
$topscrollWrapper.onscroll = e => $table.scroll((e.target as HTMLElement).scrollLeft, 0)
$table.onscroll = e => $topscrollWrapper.scroll((e.target as HTMLElement).scrollLeft, 0)
bresleveloper
fonte
0

Se você estiver usando o iscroll.js no navegador da Web ou no navegador móvel, tente:

$('#pageWrapper>div:last-child').css('top', "0px");
diyism
fonte
0

Uma diretiva AngularJs para conseguir isso: Para usá-lo, adicione a classe css double-hscroll ao seu elemento. Você precisará de jQuery e AngularJs para isso.

import angular from 'angular';

var app = angular.module('plunker', []);
app.controller('MainCtrl', function($scope, $compile) {
  $scope.name = 'Dual wielded horizontal scroller';
});

app.directive('doubleHscroll', function($compile) {
  return {
restrict: 'C',
link: function(scope, elem, attr){

  var elemWidth = parseInt(elem[0].clientWidth);

  elem.wrap(`<div id='wrapscroll' style='width:${elemWidth}px;overflow:scroll'></div>`); 
  //note the top scroll contains an empty space as a 'trick' 
  $('#wrapscroll').before(`<div id='topscroll' style='height:20px; overflow:scroll;width:${elemWidth}px'><div style='min-width:${elemWidth}px'> </div></div>`);

  $(function(){
    $('#topscroll').scroll(function(){
      $("#wrapscroll").scrollLeft($("#topscroll").scrollLeft());
    });
    $('#wrapscroll').scroll(function() {
      $("#topscroll").scrollLeft($("#wrapscroll").scrollLeft());
    });

  });  

}

  };


});
Tore Aurstad
fonte
0

Aqui está um exemplo para o VueJS

index.page

<template>
  <div>
    <div ref="topScroll" class="top-scroll" @scroll.passive="handleScroll">
      <div
        :style="{
          width: `${contentWidth}px`,
          height: '12px'
        }"
      />
    </div>
    <div ref="content" class="content" @scroll.passive="handleScroll">
      <div
        :style="{
          width: `${contentWidth}px`
        }"
      >
        Lorem ipsum dolor sit amet, ipsum dictum vulputate molestie id magna,
        nunc laoreet maecenas, molestie ipsum donec lectus ut et sit, aut ut ut
        viverra vivamus mollis in, integer diam purus penatibus. Augue consequat
        quis phasellus non, congue tristique ac arcu cras ligula congue, elit
        hendrerit lectus faucibus arcu ligula a, id hendrerit dolor nec nec
        placerat. Vel ornare tincidunt tincidunt, erat amet mollis quisque, odio
        cursus gravida libero aliquam duis, dolor sed nulla dignissim praesent
        erat, voluptatem pede aliquam. Ut et tellus mi fermentum varius, feugiat
        nullam nunc ultrices, ullamcorper pede, nunc vestibulum, scelerisque
        nunc lectus integer. Nec id scelerisque vestibulum, elit sit, cursus
        neque varius. Fusce in, nunc donec, volutpat mauris wisi sem, non
        sapien. Pellentesque nisl, lectus eros hendrerit dui. In metus aptent
        consectetuer, sociosqu massa mus fermentum mauris dis, donec erat nunc
        orci.
      </div>
    </div>
  </div>
</template>

<script>
export default {
  data() {
    return {
      contentWidth: 1000
    }
  },
  methods: {
    handleScroll(event) {
      if (event.target._prevClass === 'content') {
        this.$refs.topScroll.scrollLeft = this.$refs.content.scrollLeft
      } else {
        this.$refs.content.scrollLeft = this.$refs.topScroll.scrollLeft
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.top-scroll,
.content {
  overflow: auto;
  max-width: 100%;
}
.top-scroll {
  margin-top: 50px;
}
</style>

TOME NOTA no height: 12px.. eu fiz isso 12px por isso vai ser notado Usuários de Mac também. Mas w / windows, 0.1px é bom o suficiente

Dean Christian Armada
fonte
-1

Há um problema com a direção da rolagem: rtl. Parece que o plugin não o suporta corretamente. Aqui está o violino: violino

Observe que ele funciona corretamente no Chrome, mas em todos os outros navegadores populares a direção da barra de rolagem superior permanece à esquerda.

Vlado
fonte