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
function fix_table_header_position(){
var width_list = [];
$("th").each(function(){
width_list.push($(this).width());
});
$("tr:first").css("position", "absolute");
$("tr:first").css("z-index", "1000");
$("th, td").each(function(index){
$(this).width(width_list[index]);
});
$("tr:first").after("<tr height=" + $("tr:first").height() + "></tr>");}
This is my solution
Pure CSS (without IE11 support):
table th {
position: -webkit-sticky; // this is for all Safari (Desktop & iOS), not for Chrome
position: sticky;
top: 0;
z-index: 5;
background: #fff;
}
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.
http://plugins.jquery.com/StickyTableHeaders/
Usage info here: https://github.com/jmosbech/StickyTableHeaders
This can be achieved by using style property transform. All you have to do is wrapping your table into some div with fixed height and overflow set to auto, for example:
.tableWrapper {
overflow: auto;
height: calc( 100% - 10rem );
}
And then you can attach onscroll handler to it, here you have method that finds each table wrapped with <div class="tableWrapper"></div>
:
fixTables () {
document.querySelectorAll('.tableWrapper').forEach((tableWrapper) => {
tableWrapper.addEventListener('scroll', () => {
var translate = 'translate(0,' + tableWrapper.scrollTop + 'px)'
tableWrapper.querySelector('thead').style.transform = translate
})
})
}
And here is working example of this in action (i have used bootstrap to make it prettier): fiddle
For those who also want to support IE and Edge, here is the snippet:
fixTables () {
const tableWrappers = document.querySelectorAll('.tableWrapper')
for (let i = 0, len = tableWrappers.length; i < len; i++) {
tableWrappers[i].addEventListener('scroll', () => {
const translate = 'translate(0,' + tableWrappers[i].scrollTop + 'px)'
const headers = tableWrappers[i].querySelectorAll('thead th')
for (let i = 0, len = headers.length; i < len; i++) {
headers[i].style.transform = translate
}
})
}
}
In IE and Edge scroll is a little bit laggy... but it works
Here is answer which helps me to find out this: answer
I've tried most of these solutions, and eventually found (IMO) the best, modern, solution:
With CSS grids, you can define a 'grid', and you can finally create a nice, javascript-free, cross-browser solution for a table with a fixed header, and scrollable content. The header height can even dynamic.
CSS: Display as grid, and set the number of template-rows
:
.grid {
display: grid;
grid-template-rows: 50px auto; // For fixed height header
grid-template-rows: auto auto; // For dynamic height header
}
HTML: Create a grid container and the number of defined rows
:
<div class="grid">
<div></div>
<div></div>
</div>
Here is working example:
CSS
body {
margin: 0px;
padding: 0px;
text-align: center;
}
.table {
width: 100%;
height: 100%;
display: grid;
grid-template-rows: 50px auto;
}
.table-heading {
background-color: #ffffd;
}
.table-content {
overflow-x: hidden;
overflow-y: scroll;
}
HTML
<html>
<head>
</head>
<body>
<div class="table">
<div class="table-heading">
HEADING
</div>
<div class="table-content">
CONTENT - CONTENT - CONTENT <br/>
CONTENT - CONTENT - CONTENT <br/>
CONTENT - CONTENT - CONTENT <br/>
CONTENT - CONTENT - CONTENT <br/>
CONTENT - CONTENT - CONTENT <br/>
CONTENT - CONTENT - CONTENT <br/>
</div>
</div>
</body>
</html>
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:
$("#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.