I want to to create a table with fixed thead
and tfoot
and a scrollable tbody
!
I’ve tried several approaches, both CSS only and CSS + Javascript, but they are all weak and unreliable and I can easily break them by changing the markup in the demo.
What I want is a way to have the table to behave like a table, this means that the browser will automatically adjust columns based on the content (both at page load that in case of window resize) and that in these scenarios:
if the content of the column’s header (
thead > tr > th
) is larger than the content of the column’s body (tbody > tr > td
) and larger than the content of the column’s footer (tfoot > tr > td
) the column should resize based on the size of the column’s headerif the content of the column’s body (
tbody > tr > td
) is larger than the content of the column’s header (thead > tr > th
) and larger than the content of the column’s footer (tfoot > tr > td
) the column should resize based on the size of the column’s bodyif the content of the column’s footer (
tfoot > tr > td
) is larger than the content of the column’s header (thead > tr > th
) and larger than the content of the column’s body (tbody > tr > td
) the column should resize based on the size of the column’s footer
The table
below should clarify the scenarios:
<table> <thead> <tr> <th>Header one *leads the width* (case 1)</th> <th>Header two</th> <th>Header three</th> </tr> </thead> <tbody> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> </tbody> <tfoot> <tr> <td>Footer one</td> <td>Footer two</td> <td>Footer three *leads the width* (case 3)</td> </tr> </tfoot> </table>
I want a clean (as possible) and reliable solution that will work for the different scenarios, possibly CSS only but also JavaScript is OK (vanilla and clean JavaScript, not jQuery plugins).
I don’t care about old browser support (it would be great to have it or at least to reach a solution which can degrade gracefully on old browser but it’s optional)… I can even accept to use div
s instead of table nodes if the final solution works as expected… so in 2016, with modern browser and CSS is this possible somehow?!
EDIT:
The body should scroll vertically and the table may have any number of columns
UPDATE:
I came up with this solution: https://codepen.io/daveoncode/pen/LNomBE but I’m still not 100% satisfied. The main issue is that I can’t set different backgrounds for header and footer cells.
UPDATE 2:
it works now!
Advertisement
Answer
I finally implemented a working solution!
The relevant CSS is the following:
.wrapper { width: 90%; position: relative; border: 1px solid #000; background: #efefef; overflow: hidden; border-radius: 7px; } .container { overflow-y: auto; height: 200px; border-top: 41px solid transparent; border-bottom: 41px solid transparent; } table { border-spacing: 0; border-collapse: collapse; width: 100%; } td + td { border-left: 1px solid #fff; } td, th { border-bottom: 1px solid #fff; background: #efefef; padding: 10px; } thead tr th, tfoot tr td { height: 0; line-height: 0; margin: 0; padding-top: 0; padding-bottom: 0; color: transparent; border: none; white-space: nowrap; } thead tr th div, tfoot tr td div { position: absolute; color: #fff; height: 20px; padding: 10px; margin-left: -10px; line-height: normal; width: 100%; z-index: 2; text-align: left; font-weight: bold; } thead tr th div { border-left: 1px solid #000; border-bottom: 1px solid #000; } tfoot tr td div { border-top: 1px solid #000; } tfoot tr td div.c1, thead tr th div.c1 { background: violet; } tfoot tr td div.c2, thead tr th div.c2 { background: green; } tfoot tr td div.c3, thead tr th div.c3 { background: yellow; } thead tr th div { top: 0; } tfoot tr td div { bottom: 0; } thead tr th:first-child div, tfoot tr td:first-child div { border-left: none; }
And this is the markup:
<div class="wrapper"> <div class="container"> <table> <thead> <tr> <th> Header one *leads the width* (case 1) <div class="c1"> Header one *leads the width* (case 1) </div> </th> <th> Header two <div class="c2"> Header two </div> </th> <th> Header three <div class="c3"> Header three </div> </th> </tr> </thead> <tbody> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three [first]</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three</td> </tr> <tr> <td>Column one</td> <td>Column two *leads the width* (case 2)</td> <td>Column three [LATEST]</td> </tr> </tbody> <tfoot> <tr> <td> Footer one <div class="c1"> Footer one </div> </td> <td> Footer two <div class="c2">Footer two</div> </td> <td> Footer three *leads the width* (case 3) <div class="c3">Footer three *leads the width* (case 3)</div> </td> </tr> </tfoot> </table> </div> </div>
It works on Chrome, Firefox, Safari and IE11 (I don’t know how it behaves on older browsers). See it on codepen: https://codepen.io/daveoncode/pen/LNomBE