表格顶部和底部都有水平滚动条

211

我在页面上有一个非常大的表格,因此我决定在表格底部放置一个水平滚动条。但是我希望这个滚动条也出现在表格顶部。

模板中的内容如下:

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

这个能在HTML和CSS中实现吗?


1
我发现这个解决方案很有用。 - VARSHA DAS
是的。https://dev59.com/UGMk5IYBdhLWcg3wxAhM - Spencer May
2
现代建议:在您喜欢的框架(React、Vue等)中创建一个“remote-control-scrollbar”组件。您只需提供一个属性,即可滚动内容的ID,例如:<MyScrollbar :sourceTarget="myOrigScrollableArea">。在组件内部,您可以监视目标并对自定义滚动条进行适当的更改。然后,原始可滚动区域中发生的任何事情都会动态地反映在滚动条组件中。现在,如果您愿意,您可以复制粘贴该组件实例并创建100个滚动条,以任何方向。 - Kalnode
@VARSHADAS,用户正在询问是否仅使用HTML和CSS就可以实现。 - Pere
@SpencerMay,用户要求表格上下方都有滚动条。 - Pere
22个回答

阿里云服务器只需要99元/年,新老用户同享,点击查看详情
267
为了模拟在元素上方出现第二个水平滚动条,需要在具有水平滚动的元素上方放置一个“虚拟”的 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());
  });
});

1
你成功了吗?想要了解更多关于jQuery的内容,请参考http://api.jquery.com/scrollLeft/(当然,你也可以直接附加onscroll处理程序来完成它,而不需要使用jQuery。)为了让没有JS的用户具有优雅的退化效果,你可以通过JS将虚拟div添加到DOM中。 - StanleyH
1
是的,我已经让它工作了,我只需要将<script type="text/javascript" src="path"></script>添加到<head>中。所以每次我添加jquery时,我都需要添加@fudgey添加的那个吗?抱歉,JavaScript和jQuery对我来说仍然有点难懂。 - psoares
4
如何使 div 自动获取其内部表格的宽度?我不想手动指定 div2 的宽度,而希望它自动获取其包含的表格的宽度。 - sqlchild
4
如何使 div 自动采用其中包含的表格的宽度而不需手动指定 div2 的宽度?我不想手动指定 div2 的宽度,而是希望它自动采用其所包含的表格的宽度。 - sqlchild
2
.wrapper1 scroll() 调用 .wrapper2 scroll(),然后 .wrapper2 scroll() 又调用 .wrapper1 scroll(),接着 .wrapper1 scroll() 再次调用 .wrapper2 scroll(),那么......嗯,这不是一个无限循环吗? - HoldOffHunger
显示剩余5条评论

71

仅使用CSS的解决方案

有一种方法可以实现这一点,我没有看到任何人在这里提到过。

通过将父容器旋转 180度,再将子容器 再次旋转180度 ,滚动条将显示在顶部。

.parent {
  transform: rotateX(180deg);
  overflow-x: auto;
} 
.child {
  transform: rotateX(180deg);
}

请参考w3c存储库中的问题。


13
如果您只需要水平滚动,这是一个非常好的解决方案。但是如果您还有垂直滚动,那么垂直滚动会相反(向上拖动以向下滚动等)。 - Alex L
4
问题是如何同时在顶部和底部拥有滚动条。不过解决方案很好。 - MichalCh
1
这种方式只显示顶部滚动条...问题要求两个都显示。 - JEricaM
1
惊人的答案: - Saad Zahoor
我喜欢这个,如果你想让垂直滚动条保持在右侧,你可以翻转X轴上的div而不是旋转- transform: rotateX(180deg); - 在这里查看fiddle:https://jsfiddle.net/5Diraptor/yoq2k3m6/11/ - AutoBaker

45

尝试使用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>

7
请访问 https://github.com/avianey/jqDoubleScroll 以获取 Pawel 的出色插件的版本,该版本不需要 jQueryUI。 - fatal_error
2
链接指向一个未维护的 GitHub,其中 README 中的链接已经失效。我还没有尝试过实际的 JS。 - Paul Gorbas
这是演示 http://web.archive.org/web/20120221225342/http://suwala.eu/blog/2012/02/01/horizontal-scrollbar-top-and-bottom-element/ - Alex78191

40

不使用JQuery(2017)

因为您可能不需要JQuery,这里有一个基于@ StanleyH答案的工作原生JS版本:

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原始答案相同的注意事项。 - rap-2-h
@eladsilver 添加一个调整观察器,以监视wrapper2中的更改,并在更改时将wrapper1的宽度设置为与wrapper2相同。 - run_the_race

26
StanleyH的回答很好,但它有一个不幸的错误:点击滚动条的阴影区域不再跳转到所选内容,而是会在滚动条位置上产生一个非常小且有些烦人的增量。

经过测试:4个版本的Firefox(100%受影响),4个版本的Chrome(50%受影响)。

这里是我的jsfiddle。您可以通过拥有一个只允许一个onScroll()事件触发的开/关(true/false)变量来解决这个问题:

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调用wrapper2的scrollLeft,而wrapper2又调用wrapper1的scrollLeft,并无限重复此过程,因此我们遇到了一个无限循环的问题。或者更确切地说:用户持续滚动与wrapperx的滚动调用发生冲突,导致事件冲突,最终结果是滚动条不会跳动。

希望这能帮助其他人!


很好的解释!确实它正在执行一个无限循环。 - Ahmed Aboud

23

首先,非常好的回答,@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做得很棒,伙计。 - Clain Dsilva
为了澄清,我还必须更改代码以使用scrollWidth,以便我的代码能够正常工作,因为“div2” div中的内容宽度是由位于那里的服务器端动态内容决定的。 - AdamJones
此答案不会在顶部创建滚动条。 - Alex
没有"overflow:none;"这样的东西,应该是"overflow:visible;"。 - magento4u_com

13
一个仅使用 JavaScript 的解决方案,基于 @HoldOffHunger 和 @bobince 的答案。
<div id="data">
  ...
</div>
function doubleScroll(element) {
    const 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"));
    let running = false;
    // Keep scrollbar in sync when element size changes
    new ResizeObserver(() => {
        scrollbar.firstChild.style.width = element.scrollWidth + "px";
    }).observe(element);
    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("data"));

2
干得好。在我的情况下,我还必须减少元素的“行高”以消除额外的空间。 - jwinn
更具体地说,在scrollbar.firstChild.style.paddingTop = "1px"之后添加scrollbar.firstChild.style.lineHeight = "0px"; - kbulgrien

11

2
尽管此插件与suwala/jquery.doubleScroll插件执行相同的操作,但它具有更多选项,例如在窗口调整大小时重新计算宽度。 - Ivan Hušnjak
1
也不依赖于jQuery UI。 - tribe84
1
我会推荐这个插件,它看起来是 suwala/jquery.doubleScroll 的改进版本,并且对我很有用。 - Russell England
1
首先感谢您提供这个优秀的插件!但是我在滚动方向:rtl方面遇到了问题。它似乎无法正确支持它。如果你们中的任何javascript高手知道如何修复它,这里是fiddle链接:https://jsfiddle.net/qsn7tupc/3/ 请注意,它在Chrome中可以工作,但在其他浏览器中不行。 - Vlado

6

React+TypeScript 将rap-2-h的代码迁移到TypeScript。

import React from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { ReactNode } from 'react';
import { useRef } from 'react';

const useStyles = makeStyles((theme) => ({
  wrapper1: {
    width: '300px',
    height: '20px',
    overflowX: 'scroll',
    overflowY: 'hidden',
    border: 'none 0px black',
  },
  wrapper2: {
    width: '300px',
    height: '100px',
    overflowX: 'scroll',
    overflowY: 'hidden',
    border: 'none 0px black',
  },
  div1: {
    width: '1000px',
    height: '20px',
  },
  div2: {
    width: '1000px',
    height: '100px',
    backgroundColor: '#88FF88',
    overflow: 'auto',
  }
}));

export default function TopBottomScrollBars() {
  const classes = useStyles();
  const wrapRef1 = useRef<HTMLDivElement>(null);
  const wrapRef2 = useRef<HTMLDivElement>(null);

  const handleScroll: React.EventHandler<React.UIEvent<ReactNode>> = (event: React.UIEvent<React.ReactNode> ) => {
    const targetDiv: HTMLDivElement = event.target as HTMLDivElement;

    if(targetDiv === wrapRef1.current && wrapRef2.current) {
      wrapRef2.current.scrollLeft = targetDiv.scrollLeft;
    }
    else if(targetDiv === wrapRef2.current && wrapRef1.current) {
      wrapRef1.current.scrollLeft = targetDiv.scrollLeft;
    }
  };

  return (
    <div>
      <div ref={wrapRef1} className={classes.wrapper1} onScroll={handleScroll} >
        <div id="div1" className={classes.div1}>
      </div>
    </div>

    <div ref={wrapRef2} className={classes.wrapper2} onScroll={handleScroll}>
      <div id="div2" className={classes.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>
    </div>
  );
}

5

基于@StanleyH的解决方案,我创建了一个AngularJS指令,在jsFiddle上有演示。

使用简单:

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

针对AngularJS开发者


40
“无需jQuery”,是的,只需要一个完整框架。没问题。 - PitaJ

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,