It's a recurring question since, like, forever: how to keep the headers fixed on top when scrolling down a table?
Yes, I know that the web isn't designed to show long spreadsheet-like tables, but when a client asks for something like that (because s/he used to those old Excel documents...), you have no choice but comply.
This is to sum up the major problems and attempted solutions with fixing the headers of a table:
- a
<thead>
element can be relatively postioned, but it won't move from its position; - with
position: absolute
orfixed
, the head is "detached" from the rest of the table, and the column widths doesn't match anymore; moreover, you have to reserve some space above the table body; - this can be solved using a different table for just the headers, leaving the body in the other, but won't fix the problem of the different widths of the columns;
- you can set the columns with fixed widths, but it's not always applicable depending on your needs - i.e. in case of dynamic or unknown content;
- Javascript can adjust the widths of the columns, but accessing to properties like
offsetWidth
causes a reflow, which is a quite heavy task even for a browser like Chrome or Firefox, and adds an annoying rendering lag with even not-so-large tables but with dynamic content; - you can create a copy of the table, using the first to show the headers and the other to show the body, but this makes the DOM twice as heavy and should rely on Javascript to copy the changes of the content;
- using
<div>
s withdisplay: table-whatever
won't actually solve a thing, and deprives you of the chance to addrowspan
s andcolspan
s.
With the latest technologies of the web, maybe we can try something new. I've experimented a solution using transform: translate
which behaves acceptably good (see the fiddle here), and keeps the space above the table body, and the columns width still match.
This of course won't work in IE8 and lower. But it works fine in Chrome, Safari and Firefox. It doesn't work in Opera 12.x and below, but it does work in Opera 15 thanks of its brand new Blink render engine. I've noticed this works better or at least as well with translate
than with translate3d
: it shows a bit less flickering.
Unfortunately, this doesn't work in IE9 and IE10, and the headers are kept in their positions. It's really a shame since there's no way to detect this behaviour (that I know of).
So, what are your most recent solutions for this problem? I'm looking for CSS and pure Javascript solutions.