barre de défilement horizontale en haut et en bas du tableau

159

J'ai un très grand tablesur ma page. J'ai donc décidé de mettre une barre de défilement horizontale en bas du tableau. Mais j'aimerais que cette barre de défilement soit également au sommet de la table.

Voici ce que j'ai dans le modèle:

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

Est-ce possible de le faire uniquement en HTML et CSS?

psoares
la source
1
stackoverflow.com/questions/2274627/... J'ai trouvé cette solution utile.
VARSHA DAS

Réponses:

234

Pour simuler une deuxième barre de défilement horizontale au-dessus d'un élément, placez un "factice" divau-dessus de l'élément qui a un défilement horizontal, juste assez haut pour une barre de défilement. Ensuite, attachez les gestionnaires de l'événement "scroll" pour l'élément factice et l'élément réel, pour obtenir l'autre élément synchronisé lorsque l'une des barres de défilement est déplacée. L'élément factice ressemblera à une deuxième barre de défilement horizontale au-dessus de l'élément réel.

Pour un exemple en direct , voyez ce violon

Voici le code :

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
la source
vraiment bonne réponse! Merci beaucoup! :) donc j'ai essayé d'utiliser votre exemple, mais la barre en haut ne fonctionne pas, et quand j'ai essayé d'augmenter la largeur, la barre de défilement disparaît. une idée pourquoi?
psoares
1
L'avez-vous fait fonctionner? Pour plus d'informations sur jQuery, voir api.jquery.com/scrollLeft (Bien sûr, vous pouvez le faire sans jQuery en attachant directement les gestionnaires onscroll.) Pour une dégradation gracieuse pour les utilisateurs sans JS, vous pouvez ajouter le div factice au DOM par JS .
StanleyH
1
oui je l'ai fait fonctionner, je n'avais qu'a ajouter <script type = "text / javascript" src = "path"> </script> à <head>. Donc à chaque fois que j'ajoute jquery, je devais ajouter celui que @fudgey ajoute? Désolé, javascript et jquery sont toujours un peu chinois pour moi
psoares
4
@StanleyH: comment définir le div pour qu'il prenne automatiquement la largeur du tableau à l'intérieur? Je ne veux pas spécifier la largeur de div2 manuellement, mais je veux qu'il prenne automatiquement la largeur du tableau qu'il contient.
sqlchild
3
@CodyGuldner: comment définir le div pour qu'il prenne automatiquement la largeur du tableau à l'intérieur? Je ne veux pas spécifier la largeur de div2 manuellement, mais je veux qu'il prenne automatiquement la largeur du tableau qu'il contient.
sqlchild
38

Essayez d'utiliser le 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
la source
5
Voir github.com/avianey/jqDoubleScroll pour une version du plugin génial de Pawel qui ne nécessite pas jQueryUI.
fatal_error
1
Le lien mène à un GitHub non maintenu avec des liens cassés dans read me. Je n'ai pas essayé les js réels.
Paul Gorbas
19

Tout d'abord, bonne réponse, @StanleyH. Si quelqu'un se demande comment créer le conteneur à double défilement avec une largeur dynamique:

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>

démo

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

simo
la source
3
Utilisez $('.div1').width( $('.div1')[0].scrollWidth)pour obtenir la largeur de défilement réelle du contenu, utile lorsque vous n'utilisez pas spécifiquement un conteneur comme une table. @simo Excellent compagnon d'effort.
Clain Dsilva
Pour clarifier, j'ai également dû changer le code en scrollWidth pour que mon propre code fonctionne là où la largeur du contenu dans le div "div2" était variable en raison du contenu dynamique côté serveur qui s'y trouvait.
AdamJones
15

Sans JQuery (2017)

Comme vous n'avez peut-être pas besoin de JQuery, voici une version fonctionnelle de Vanilla JS basée sur la réponse @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
la source
ce n'est en fait pas réactif / dynamique dans le cas où vous ne connaissez pas votre largeur
elad silver
Oui! il a les mêmes mises en garde que la réponse originale de @StanleyH
rap-2-h
11

Vous pouvez utiliser un plugin jQuery qui fera le travail pour vous:

Le plugin gérera toute la logique pour vous.

avianey
la source
2
Bien que ce plugin fasse la même chose que le plugin suwala / jquery.doubleScroll, il a plus d'options comme le recalcul de la largeur sur window.resize
Ivan Hušnjak
1
Ne dépend pas non plus de l'interface utilisateur jquery.
tribe84
1
Je recommanderais ce plugin, il ressemble à une version améliorée de suwala / jquery.doubleScroll et fonctionne pour moi
Russell England
Tout d'abord merci pour le super plugin! Cependant, j'ai un problème avec la direction de défilement: rtl. Il semble qu'il ne le supporte pas correctement. Si l'un de vous les gourous de javascripts sait comment y remédier, voici le violon: jsfiddle.net/qsn7tupc/3 Notez que cela fonctionne dans Chrome mais dans aucun autre navigateur.
Vlado
10

La réponse de StanleyH était excellente, mais il y avait un bogue malheureux: cliquer sur la zone ombrée de la barre de défilement ne saute plus à la sélection sur laquelle vous cliquez. Au lieu de cela, vous obtenez un incrément très petit et quelque peu ennuyeux dans la position de la barre de défilement.

Testé: 4 versions de Firefox (affectées à 100%), 4 versions de Chrome (affectées à 50%).

Voici mon jsfiddle . Vous pouvez contourner ce problème en ayant une var on / off (vrai / faux) qui permet à un seul événement onScroll () de se déclencher à la fois:

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());
});

Comportement du problème avec réponse acceptée:

Comportement réellement souhaité:

Alors, pourquoi cela se produit-il? Si vous parcourez le code, vous verrez que wrapper1 appelle scrollLeft de wrapper2, et wrapper2 appelle scrollLeft de wrapper1, et répétez cela indéfiniment, nous avons donc un problème de boucle infinie. Ou plutôt: le défilement continu de l'utilisateur entre en conflit avec l'appel de wrapperx du défilement, un conflit d'événement se produit et le résultat final n'est pas de sauter dans les barres de défilement.

J'espère que cela aide quelqu'un d'autre!

HoldOffHunger
la source
bonne explication! en effet, il faisait une boucle infinie
Ahmed Aboud
Ouais. Merci beaucoup pour votre aide! Cela m'est utile.
Giang D.MAI
3

Lier les scrollers fonctionnait, mais de la manière dont il est écrit, cela crée une boucle qui ralentit le défilement dans la plupart des navigateurs si vous cliquez sur la partie de la barre de défilement plus claire et maintenez-la enfoncée (pas lorsque vous faites glisser le défilement).

Je l'ai corrigé avec un drapeau:

$(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
la source
Cela résout un problème que j'avais avec les réponses suggérées ici aussi. Cependant, cela ne fait qu'atténuer légèrement le problème, il peut toujours y avoir un défilement progressif / lent si la distance que vous souhaitez faire défiler est suffisamment grande pour cela.
Dan Temple
Avec le conditionnel / flag, cette solution fonctionne bien et les tests correspondent au comportement auquel vous vous attendez sans l'application de JavaScript dans le navigateur.
userabuser
3

une solution javascript uniquement basée sur les réponses @HoldOffHunger et @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
la source
3

Basé sur la solution @StanleyH, j'ai créé une directive AngularJS , une démonstration sur jsFiddle .

Facile à utiliser:

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

Pour les développeurs AngularJS

przno
la source
31
"Aucun jQuery requis." Ouais, juste un cadre complet. Pas de problème.
PitaJ
2

Autant que je sache, cela n'est pas possible avec HTML et CSS.

punkrockbuddyholly
la source
Eh
Pour HTML et CSS, il n'y a pas de meilleur moyen. Ce n'est tout simplement pas possible. Vous devez utiliser d'autres techniques, comme javascript, pour obtenir ce type de fonctionnalité.
Justus Romijn
1
pouvez-vous donner quelques conseils pour commencer à chercher?
psoares
2
Cela ne répond pas à la question. Pour critiquer ou demander des éclaircissements à un auteur, laissez un commentaire sous sa publication.
SSA
2
@SSA répond à la question. La question était "Est-ce possible de le faire uniquement en HTML et CSS?" et la réponse à cela est «non».
punkrockbuddyholly
2

En Javascript / Angular vanille, vous pouvez faire ceci comme ceci:

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
la source
1

En développant la réponse de StanleyH et en essayant de trouver le minimum requis, voici ce que j'ai implémenté:

JavaScript (appelé une fois de quelque part comme $(document).ready()):

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

HTML (notez que les largeurs changeront la longueur de la barre de défilement):

<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>

C'est tout.

MattC
la source
1

à tous les fans angular / nativeJs, en implémentant la réponse de @ simo

HTML (pas de changement)

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

CSS (pas de changement, largeur: 90% est ma conception)

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

JS (comme onload) ou ngAfterViewChecked(tous les assont pour 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)
développeur
la source
0

Si vous utilisez iscroll.js sur un navigateur Webkit ou un navigateur mobile, vous pouvez essayer:

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

Une directive AngularJs pour y parvenir: Pour l'utiliser, ajoutez la classe css double-hscroll à votre élément. Vous aurez besoin de jQuery et AngularJs pour cela.

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
la source
0

Voici un exemple pour VueJS

sommaire

<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>

PRENEZ NOTE sur le height: 12px.. Je l'ai fait 12px donc il sera également remarqué sur les utilisateurs Mac. Mais avec windows, 0.1px est assez bon

Dean Christian Armada
la source
-1

Il y a un problème avec la direction de défilement: rtl. Il semble que le plugin ne le supporte pas correctement. Voici le violon: violon

Notez que cela fonctionne correctement dans Chrome, mais dans tous les autres navigateurs populaires, la direction de la barre de défilement supérieure reste à gauche.

Vlado
la source