горизонтальная полоса прокрутки сверху и снизу стола


159

У меня очень большой tableна моей странице. Поэтому я решил поставить горизонтальную полосу прокрутки в нижней части таблицы. Но я бы хотел, чтобы эта полоса прокрутки была также сверху на столе.

Что я имею в шаблоне это:

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

Это возможно сделать только в HTML и CSS?


1
stackoverflow.com/questions/2274627/… Я нашел это решение полезным.
Варша дас

Ответы:


234

Чтобы смоделировать вторую горизонтальную полосу прокрутки поверх элемента, поместите «пустышку» divнад элементом, имеющим горизонтальную прокрутку, достаточно высоко для полосы прокрутки. Затем присоедините обработчики события «scroll» для фиктивного элемента и реального элемента, чтобы синхронизировать другой элемент при перемещении полосы прокрутки. Фиктивный элемент будет выглядеть как вторая горизонтальная полоса прокрутки над реальным элементом.

Для живого примера , см. Эту скрипку

Вот код :

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

действительно отличный ответ! большое спасибо! :) поэтому я попытался использовать ваш пример, но полоса сверху не работает, и когда я попытался увеличить ширину, полоса прокрутки исчезла. есть идеи почему?
psoares

1
Вы заставили это работать? Для получения дополнительной информации о jQuery см. Api.jquery.com/scrollLeft (Конечно, вы можете сделать это без jQuery, напрямую подключая обработчики onscroll.) Для постепенного снижения производительности для пользователей без JS вы можете добавить фиктивный div в DOM с помощью JS ,
СтэнлиХ

1
да, я получил его на работу, мне нужно было только добавить <script type = "text / javascript" src = "path"> </ script> в <head>. Таким образом, каждый раз, когда я добавляю jquery, мне приходилось добавлять тот, который @fudgey add? Извините, javascript и jquery для меня все еще своего рода китайский язык
psoares

4
@StanleyH: как настроить div для автоматического определения ширины таблицы внутри него? я не хочу указывать ширину div2 вручную, но хочу, чтобы он автоматически брал ширину таблицы, которую он содержит.
sqlchild

3
@CodyGuldner: как настроить div для автоматического определения ширины таблицы внутри него? я не хочу указывать ширину div2 вручную, но хочу, чтобы он автоматически брал ширину таблицы, которую он содержит.
sqlchild

38

Попробуйте использовать jquery.doubleScrollплагин :

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>

5
См github.com/avianey/jqDoubleScroll для версии удивительного плагина Pawel, что не требует jQueryUI.
fatal_error

1
Ссылка приводит к необслуживаемому GitHub с неработающими ссылками в read me. Не пробовал настоящий JS.
Пол Горбас

19

Прежде всего, отличный ответ, @StanleyH. Если кому-то интересно, как сделать контейнер с двойной прокруткой с динамической шириной:

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>

демонстрация

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


3
Используйте, $('.div1').width( $('.div1')[0].scrollWidth)чтобы получить реальную ширину прокрутки содержимого, полезно, если вы не используете контейнер, подобный таблице. @Simo Потрясающий помощник усилий.
Клин Дсилва

Чтобы уточнить, мне также пришлось изменить код на scrollWidth, чтобы мой собственный код работал там, где ширина содержимого в div "div2" была переменной из-за расположенного там динамического содержимого на стороне сервера.
AdamJones

15

Без JQuery (2017)

Поскольку вам может не понадобиться JQuery, вот рабочая версия Vanilla JS, основанная на ответе @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>


это на самом деле не отзывчиво / динамично в случае, если вы не знаете свою ширину
elad silver

да! он имеет те же предостережения, что и первоначальный ответ @StanleyH
рэп-2-ч

11

Вы можете использовать плагин jQuery, который сделает всю работу за вас:

Плагин будет обрабатывать всю логику для вас.


2
Хотя этот плагин делает то же самое, что и плагин suwala / jquery.doubleScroll, у него есть больше опций, таких как пересчет ширины в window.resize
Иван Гушняк

1
Также не зависит от jquery UI.
tribe84

1
Я бы порекомендовал этот плагин, он выглядит как улучшенная версия suwala / jquery.doubleScroll и работает для меня
Russell England

Сначала спасибо за отличный плагин! Однако у меня есть проблема с направлением прокрутки: RTL. Кажется, это не поддерживает это правильно. Если кто-то из вас, гуру javascripts, знает, как это исправить, вот скрипка: jsfiddle.net/qsn7tupc/3 Обратите внимание, что он работает в Chrome, но ни в каком другом браузере.
Владо

10

Ответ StanleyH был превосходным, но у него была одна неприятная ошибка: нажатие на затененную область полосы прокрутки больше не переходит к выбранному вами выбору. Вместо этого вы получите очень маленький и несколько раздражающий прирост положения полосы прокрутки.

Протестировано: 4 версии Firefox (затронуты на 100%), 4 версии Chrome (затронуты на 50%).

Вот мой jsfiddle . Вы можете обойти это, имея переменную on / off (true / false), которая позволяет запускать одновременно только одно событие onScroll ():

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

Поведение проблемы с принятым ответом:

Фактически желаемое поведение:

Так почему же это происходит?Если вы выполните код, вы увидите, что wrapper1 вызывает scrollLeft для wrapper2, а wrapper2 вызывает scrollLeft для wrapper1 и повторяет это бесконечно, поэтому у нас возникает проблема с бесконечным циклом. Или, скорее: продолжающаяся прокрутка пользователя конфликтует с вызовом прокрутки от wrapperx, возникает конфликт событий, и конечным результатом является отсутствие скачков в полосах прокрутки.

Надеюсь, это поможет кому-то еще!


отличное объяснение! на самом деле это делал бесконечный цикл
Ахмед Абуд

Да. Спасибо большое за Вашу поддержку! Это полезно для меня.
Гианг Д.Май

3

Связывание скроллеров работало, но в том виде, в котором оно написано, оно создает цикл, который замедляет прокрутку в большинстве браузеров, если вы нажимаете на часть более легкой полосы прокрутки и удерживаете ее (а не при перетаскивании скроллера).

Я исправил это с флагом:

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

Это решает проблему, которую я имел с предложенными здесь ответами. Тем не менее, это только немного смягчает проблему, может все же быть пошаговая / медленная прокрутка, если расстояние, которое вы хотите прокрутить, достаточно велико для нее.
Дан Темпл

С условным / флагом это решение работает хорошо, и тесты соответствуют поведению, которое вы ожидаете без применения JavaScript в браузере.
userabuser

3

решение только для javascript, основанное на ответах @HoldOffHunger и @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'));

3

На основе решения @StanleyH я создал директиву AngularJS , демо-версию для jsFiddle .

Легко использовать:

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

Для разработчиков AngularJS


31
"Не требуется jQuery." Да, просто целые рамки. Нет, важная персона
PitaJ

2

Насколько я знаю, это невозможно с HTML и CSS.


ну, это на самом деле то, что я думал .. Но я хотел бы знать, если кто-то сделал это, и лучший способ сделать это ..
psoares

Для HTML и CSS не существует лучшего способа. Это просто невозможно. Вам нужно использовать другие методы, такие как JavaScript, чтобы получить такую ​​функциональность.
Юстус Ромейн

1
Можете ли вы дать несколько советов, чтобы начать искать?
psoares

2
Это не дает ответа на вопрос. Чтобы критиковать или запросить разъяснения у автора, оставьте комментарий под своим постом.
SSA

2
@SSA это действительно отвечает на вопрос. Вопрос был: «Это возможно сделать только в HTML и CSS?» и ответ на это "нет".
punkrockbuddyholly

2

В ванильном Javascript / Angular вы можете сделать это следующим образом:

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

1

Расширяя ответ Стэнли и пытаясь найти необходимый минимум, вот что я реализовал:

JavaScript (вызывается один раз откуда-то вроде $(document).ready()):

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

HTML (обратите внимание, что ширина будет изменять длину полосы прокрутки):

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

Вот и все.


1

всем поклонникам angular / nativeJs, реализующим ответ @ simo

HTML (без изменений)

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

CSS (без изменений, ширина: 90% - мой дизайн)

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

JS (как onload) или ngAfterViewChecked(все asдля 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)

0

Если вы используете iscroll.js в веб-браузере или мобильном браузере, вы можете попробовать:

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

0

Директива AngularJs для достижения этой цели: чтобы использовать ее, добавьте класс css double-hscroll к вашему элементу. Для этого вам понадобятся jQuery и AngularJ.

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

  });  

}

  };


});

0

Вот пример для 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>

ЗАМЕТЬТЕ на height: 12px.. Я сделал это 12px, чтобы это было замечено и для пользователей Mac. Но с окнами 0.1px достаточно хорош


-1

Существует проблема с направлением прокрутки: RTL. Кажется, плагин не поддерживает его правильно. Вот скрипка: скрипка

Обратите внимание, что в Chrome он работает правильно, но во всех других популярных браузерах направление верхней полосы прокрутки остается левым.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.