After researching this for the last few hours, I'm beginning to think this is impossible, even on the most up-to-date browsers:
HTML table element with a horizontal scroll, with a "sticky" thead on the top, as part of a surrounding web page that scrolls vertically.
Here's my attempt:
#a {
height: 100px;
background-color: green;
}
body {
width: 100%;
}
#wrapper {
overflow-x: scroll;
width: 100%;
}
th {
position:sticky;
top: 0;
background-color: red;
z-index: 1;
}
td {
white-space: nowrap;
}
#b {
height: 2000px;
background-color: blue;
}
<div id="a">
some content
</div>
<div id="wrapper">
<table id="test">
<thead>
<tr>
<th>sticky header</th>
<th>sticky header</th>
<th>sticky header</th>
</tr>
</thead>
<tbody>
<tr>
<td>long content long content long content long content long content long content</td>
<td>long content long content long content long content long content long content</td>
<td>long content long content long content long content long content long content</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>
</div>
<div id="b">
some more content
</div>
(There's also this fiddle, so you can mess with the code)
The way it currently is, the "position: sticky" doesn't work when the #wrapper is overflow-x: scroll. If you remove the overflow-x rule, it works, but then of course the table expands the width of the entire page (which is definitely not cool)
I know making the table the "scrolling" element would fix the issue, but that's not desirable either (I only want the web page body to be scrollable vertically).
I've tried to come up with alternate CSS solutions, and even Javascript solutions, but I can't think of a solution that would ultimately work. Is this actually impossible?
While I'd prefer a css solution, I'm open to a javascript solution at this point.
Have a fiddle with a working example. You could even get rid of some of the javascript by declaring width/height beforehand.
Added some ids to your original example
<div id="a">
some content
</div>
<div id="wrapper">
<table id="test">
<thead id="sticky">
<tr id="headerRow">
<th>sticky header</th>
<th>sticky header</th>
<th>sticky header</th>
</tr>
</thead>
<tbody>
<tr>
<td>long content long content long content long content long content long content</td>
<td>long content long content long content long content long content long content</td>
<td>long content long content long content long content long content long content</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
<tr>
<td>1</td>
<td>2</td>
<td>3</td>
</tr>
</tbody>
</table>
</div>
<div id="b">
some more content
</div>
Below is the javascript
// When the user scrolls the page, execute addSticky
window.onscroll = function() {addSticky()};
document.getElementById("wrapper").onscroll = function(){addSticky()};
// Get the header
var header = document.getElementById("sticky");
// Get the offset position
var sticky = header.offsetTop;
// Get bottom offset
var bottomOffset = document.getElementById("test").offsetHeight+100;
// Set the width of the row and columns by placing them in an array and looping said array
var headerRow = document.getElementById("headerRow");
header.style.width = headerRow.offsetWidth+"px";
var headerKids = headerRow.children;
for (var i=0; i<headerKids.length; i++){
headerKids[i].style.width=headerKids[i].offsetWidth+"px";
}
// Add the sticky class to the header when you reach its scroll position. Remove "sticky" when you leave the scroll position
function addSticky() {
if (this.scrollY > 100 && this.scrollY < bottomOffset ) {
xScroll = document.getElementById("wrapper").scrollLeft;
header.classList.add("sticky");
header.style.left = "-"+xScroll+"px";
} else {
header.classList.remove("sticky");
}
}
Updates to CSS
.sticky {
position: fixed;
top: 0;
height: 20px;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With