当用户使用 jQuery 将其滚动到视图之外时,表头保持固定在顶部
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4709390/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Table header to stay fixed at the top when user scrolls it out of view with jQuery
提问by
I am trying to design an HTML table where the header will stay at the top of the page when AND ONLY when the user scrolls it out of view. For example, the table may be 500 pixels down from the page, how do I make it so that if the user scrolls the header out of view (browser detects its no longer in the windows view somehow), it will stay put at the top? Anyone can give me a Javascript solution to this?
我正在尝试设计一个 HTML 表格,当且仅当用户将其滚动到视图之外时,标题将保留在页面顶部。例如,表格可能距页面 500 像素,我该如何制作,以便如果用户将标题滚动到视图之外(浏览器检测到它不再以某种方式出现在 Windows 视图中),它将保持在顶部? 任何人都可以给我一个 Javascript 解决方案吗?
<table>
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
</tr>
</thead>
<tbody>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
</tbody>
</table>
So in the above example, I want the <thead>
to scroll with the page if it goes out of view.
所以在上面的例子中,<thead>
如果页面不在视图中,我希望随着页面滚动。
IMPORTANT: I am NOTlooking for a solution where the <tbody>
will have a scrollbar (overflow:auto).
重要提示:我不是在寻找<tbody>
具有滚动条(溢出:自动)的解决方案。
采纳答案by Andrew Whitaker
You would do something like this by tapping into the scroll
event handler on window
, and using another table
with a fixed position to show the header at the top of the page.
您可以通过点击 上的scroll
事件处理程序window
并使用另一个table
具有固定位置的事件处理程序来执行类似的操作,以在页面顶部显示标题。
HTML:
HTML:
<table id="header-fixed"></table>
CSS:
CSS:
#header-fixed {
position: fixed;
top: 0px; display:none;
background-color:white;
}
JavaScript:
JavaScript:
var tableOffset = $("#table-1").offset().top;
var $header = $("#table-1 > thead").clone();
var $fixedHeader = $("#header-fixed").append($header);
$(window).bind("scroll", function() {
var offset = $(this).scrollTop();
if (offset >= tableOffset && $fixedHeader.is(":hidden")) {
$fixedHeader.show();
}
else if (offset < tableOffset) {
$fixedHeader.hide();
}
});
This will show the table head when the user scrolls down far enough to hide the original table head. It will hide again when the user has scrolled the page up far enough again.
当用户向下滚动到足以隐藏原始表头时,这将显示表头。当用户再次向上滚动页面时,它将再次隐藏。
Working example: http://jsfiddle.net/andrewwhitaker/fj8wM/
回答by entropy
Well, I was trying to obtain the same effect without resorting to fixed size columns or having a fixed height for the entire table.
好吧,我试图在不使用固定大小的列或为整个表格设置固定高度的情况下获得相同的效果。
The solution I came up with is a hack. It consists of duplicating the entire table then hiding everything but the header, and making that have a fixed position.
我想出的解决方案是一个黑客。它包括复制整个表格,然后隐藏除标题之外的所有内容,并使其具有固定位置。
HTML
HTML
<div id="table-container">
<table id="maintable">
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
</tr>
</thead>
<tbody>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>some really long line here instead</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
</tbody>
</table>
<div id="bottom_anchor"></div>
</div>
CSS
CSS
body { height: 1000px; }
thead{
background-color:white;
}
javascript
javascript
function moveScroll(){
var scroll = $(window).scrollTop();
var anchor_top = $("#maintable").offset().top;
var anchor_bottom = $("#bottom_anchor").offset().top;
if (scroll>anchor_top && scroll<anchor_bottom) {
clone_table = $("#clone");
if(clone_table.length == 0){
clone_table = $("#maintable").clone();
clone_table.attr('id', 'clone');
clone_table.css({position:'fixed',
'pointer-events': 'none',
top:0});
clone_table.width($("#maintable").width());
$("#table-container").append(clone_table);
$("#clone").css({visibility:'hidden'});
$("#clone thead").css({'visibility':'visible','pointer-events':'auto'});
}
} else {
$("#clone").remove();
}
}
$(window).scroll(moveScroll);
See here: http://jsfiddle.net/QHQGF/7/
见这里:http: //jsfiddle.net/QHQGF/7/
Edit: updated the code so that the thead can receive pointer events(so buttons and links in the header still work). This fixes the problem reported by luhfluh and Joe M.
编辑:更新了代码,以便 thead 可以接收指针事件(因此标题中的按钮和链接仍然有效)。这解决了 luhfluh 和 Joe M. 报告的问题。
New jsfiddle here: http://jsfiddle.net/cjKEx/
新 jsfiddle 在这里:http: //jsfiddle.net/cjKEx/
回答by Ihor Zenich
Pure CSS (without IE11 support):
纯 CSS(不支持 IE11):
table th {
position: -webkit-sticky; // this is for all Safari (Desktop & iOS), not for Chrome
position: sticky;
top: 0;
z-index: 5;
background: #fff;
}
回答by mkoryak
I wrote a plugin that does this. Ive been working on it for about a year now and I think it handles all the corner cases pretty well:
我写了一个插件来做到这一点。我已经研究它大约一年了,我认为它可以很好地处理所有极端情况:
- scrolling within a container with overflow
- scrolling within a window
- taking care of what happens when you resize the window
- keeping your events bound to the header
- most importantly it doesn't force you to change your table's cssto make it work
- 在溢出的容器内滚动
- 在窗口内滚动
- 注意调整窗口大小时会发生什么
- 保持您的事件绑定到标题
- 最重要的是,它不会强迫您更改表格的 css以使其正常工作
Here are some demos/docs:
http://mkoryak.github.io/floatThead/
这里有一些演示/文档:http:
//mkoryak.github.io/floatThead/
回答by rockusbacchus
I was able to fix the problem with changing column widths. I started with Andrew's solution above (thanks so much!) and then added one little loop to set the widths of the cloned td's:
我能够通过更改列宽来解决问题。我从上面的 Andrew 解决方案开始(非常感谢!)然后添加一个小循环来设置克隆 td 的宽度:
$("#header-fixed td").each(function(index){
var index2 = index;
$(this).width(function(index2){
return $("#table-1 td").eq(index).width();
});
});
This solves the problem without having to clone the entire table and hide the body. I'm brand new to JavaScript and jQuery (and to stack overflow), so any comments are appreciated.
这解决了问题,而不必克隆整个表并隐藏正文。我是 JavaScript 和 jQuery 的新手(以及堆栈溢出),因此感谢任何评论。
回答by josephting
This is by far the best solution I've found for having a fixed table header.
这是迄今为止我找到的具有固定表头的最佳解决方案。
UPDATE 5/11: Fixed horizontal scrolling bug as pointed out by Kerry Johnson
更新 5/11:修复了Kerry Johnson指出的水平滚动错误
Codepen: https://codepen.io/josephting/pen/demELL
代码笔:https://codepen.io/josephting/pen/demELL
;(function($) {
$.fn.fixMe = function() {
return this.each(function() {
var $this = $(this),
$t_fixed;
function init() {
$this.wrap('<div class="container" />');
$t_fixed = $this.clone();
$t_fixed.find("tbody").remove().end().addClass("fixed").insertBefore($this);
resizeFixed();
}
function resizeFixed() {
$t_fixed.width($this.outerWidth());
$t_fixed.find("th").each(function(index) {
$(this).css("width",$this.find("th").eq(index).outerWidth()+"px");
});
}
function scrollFixed() {
var offsetY = $(this).scrollTop(),
offsetX = $(this).scrollLeft(),
tableOffsetTop = $this.offset().top,
tableOffsetBottom = tableOffsetTop + $this.height() - $this.find("thead").height(),
tableOffsetLeft = $this.offset().left;
if(offsetY < tableOffsetTop || offsetY > tableOffsetBottom)
$t_fixed.hide();
else if(offsetY >= tableOffsetTop && offsetY <= tableOffsetBottom && $t_fixed.is(":hidden"))
$t_fixed.show();
$t_fixed.css("left", tableOffsetLeft - offsetX + "px");
}
$(window).resize(resizeFixed);
$(window).scroll(scrollFixed);
init();
});
};
})(jQuery);
$(document).ready(function(){
$("table").fixMe();
$(".up").click(function() {
$('html, body').animate({
scrollTop: 0
}, 2000);
});
});
body{
font:1.2em normal Arial,sans-serif;
color:#34495E;
}
h1{
text-align:center;
text-transform:uppercase;
letter-spacing:-2px;
font-size:2.5em;
margin:20px 0;
}
.container{
width:90%;
margin:auto;
}
table{
border-collapse:collapse;
width:100%;
}
.blue{
border:2px solid #1ABC9C;
}
.blue thead{
background:#1ABC9C;
}
.purple{
border:2px solid #9B59B6;
}
.purple thead{
background:#9B59B6;
}
thead{
color:white;
}
th,td{
text-align:center;
padding:5px 0;
}
tbody tr:nth-child(even){
background:#ECF0F1;
}
tbody tr:hover{
background:#BDC3C7;
color:#FFFFFF;
}
.fixed{
top:0;
position:fixed;
width:auto;
display:none;
border:none;
}
.scrollMore{
margin-top:600px;
}
.up{
cursor:pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>↓ SCROLL ↓</h1>
<table class="blue">
<thead>
<tr>
<th>Colonne 1</th>
<th>Colonne 2</th>
<th>Colonne 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Non</td>
<td>MaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMaisMais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
</tbody>
</table>
<h1 class="scrollMore">↓ SCROLL MORE ↓</h1>
<table class="purple">
<thead>
<tr>
<th>Colonne 1</th>
<th>Colonne 2</th>
<th>Colonne 3</th>
</tr>
</thead>
<tbody>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
<tr>
<td>Non</td>
<td>Mais</td>
<td>Allo !</td>
</tr>
</tbody>
</table>
<h1 class="up scrollMore">↑ UP ↑</h1>
回答by Janning
Best solution is to use this jquery plugin:
最好的解决方案是使用这个 jquery 插件:
https://github.com/jmosbech/StickyTableHeaders
https://github.com/jmosbech/StickyTableHeaders
This plugin worked great for us and we tried a lot other solutions. We tested it in IE, Chrome and Firefox
这个插件对我们很有用,我们尝试了很多其他的解决方案。我们在 IE、Chrome 和 Firefox 中对其进行了测试
回答by Srivats Shankar
There are many really good solution here already. But one of the simplest CSS only solutions that I use in these situations is as follows:
这里已经有很多非常好的解决方案。但我在这些情况下使用的最简单的 CSS 解决方案之一如下:
table {
/* Not required only for visualizing */
border-collapse: collapse;
width: 100%;
}
table thead tr th {
/* Important */
background-color: red;
position: sticky;
z-index: 100;
top: 0;
}
td {
/* Not required only for visualizing */
padding: 1em;
}
<table>
<thead>
<tr>
<th>Col1</th>
<th>Col2</th>
<th>Col3</th>
</tr>
</thead>
<tbody>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
<tr>
<td>info</td>
<td>info</td>
<td>info</td>
</tr>
</tbody>
</table>
Because there is no requirement for JavaScript it simplifies the situation significantly. You essentially need to focus on the secondCSS rule, which contains the conditions for ensuring that the head of the table remains of the top no matter the scroll space.
因为不需要 JavaScript,所以它大大简化了情况。您基本上需要关注第二条CSS 规则,它包含确保无论滚动空间如何,表头都保持在顶部的条件。
To elaborate on each of the rules in detail. position
is meant to indicate to the browser that the head object, its row, and its cells all need to stick to the top. This necessarily needs to be accompanied by top
, which specifies to the browser that the head will stick to the top of the page or viewport. Additionally, you can add z-index
to ensure that the content of the head always remains on the top.
详细阐述每条规则。position
是为了向浏览器表明头部对象、它的行和它的单元格都需要贴在顶部。这必然需要伴随top
,它向浏览器指定头部将贴在页面或视口的顶部。此外,您可以添加z-index
以确保头部的内容始终保留在顶部。
The background colour is merely to illustrate the point. You do not need to use any additional JavaScript to get this effect. This is supported in most major browsers after 2016.
背景颜色只是为了说明这一点。您无需使用任何额外的 JavaScript 即可获得此效果。2016 年之后的大多数主要浏览器都支持此功能。
回答by Lok Yan Wong
I found a simple jQuery library called Sticky Table Headers. Two lines of code and it did exactly what I wanted. The solutions above don't manage the column widths, so if you have table cells that take up a lot of space, the resulting size of the persistent header will not match your table's width.
我找到了一个名为 Sticky Table Headers 的简单 jQuery 库。两行代码,它完全符合我的要求。上面的解决方案不管理列宽,因此如果您有占用大量空间的表格单元格,则持久标题的结果大小将与表格的宽度不匹配。
http://plugins.jquery.com/StickyTableHeaders/
http://plugins.jquery.com/StickyTableHeaders/
Usage info here: https://github.com/jmosbech/StickyTableHeaders
回答by Vitalii Maslianok
Well, after reviewing all available solutions I wrote plugin which can freeze any row (not only th) at the top of page or container. It's very simple and very fast. Feel free to use it. http://maslianok.github.io/stickyRows/
好吧,在查看了所有可用的解决方案后,我编写了插件,该插件可以冻结页面或容器顶部的任何行(不仅是 th)。它非常简单且非常快速。随意使用它。 http://maslianok.github.io/stickyRows/