In this particular case, the <tbody>
functions as the viewport, requiring the rows to have display: table
in order to manually set their widths.
To address this issue, I've implemented some JavaScript code that clones and appends the top rows with the most content as hidden rows within the <thead>
. Additionally, I have adjusted the CSS for better styling. However, please note that the layout may still break if the content of <th>
is longer than that of <td>
.
$(function() {
var $table = $('table');
var $body = $table.find('tbody');
var rowTexts = $body.find('tr').map(function() {
return $(this).text().trim();
}).toArray().sort(function(a, b) {
return (a.length > b.length) ? -1 : (a.length < b.length) ? 1 : 0;
});
if (rowTexts.length > 5) {
rowTexts = rowTexts.slice(0, 5);
}
var $head = $table.find('thead');
rowTexts.forEach(function(text) {
var $hiddenRow = $body.find('tr:contains(' + text + ')').clone().addClass('hidden');
$head.append($hiddenRow);
});
});
body {
height: 100%;
margin: 0;
padding: 0;
}
table {
border-collapse: collapse;
text-align: left;
margin-top: 44px;
width: 100%;
}
td,
th {
border-bottom: 1px solid black;
height: 44px;
line-height: 44px;
padding: 0 1em;
}
tr.hidden td {
border: 0;
height: 0;
line-height: 0;
overflow: hidden;
}
thead {
display: table;
position: fixed;
top: 0;
width: 100%;
}
thead tr:not(.hidden) {
background: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<table>
<thead>
<tr>
<th>Key</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>Key that's longer than usual</td>
<td>Value</td>
</tr>
<tr>
<td>Key</td>
<td>Value that's longer than usual</td>
</tr>
<tr>
<td>Key</td>
<td>Value</td>
</tr>
<tr>
<td>Key</td>
<td>Value</td>
</tr>
<tr>
<td>Key</td>
<td>Value</td>
</tr>
<tr>
<td>Key</td>
<td>Value</td>
</tr>
<tr>
<td>Key</td>
<td>Value</td>
</tr>
<tr>
<td>Key</td>
<td>Value</td>
</tr>
<tr>
<td>Key</td>
<td>Value</td>
</tr>
<tr>
<td>Key</td>
<td>Value</td>
</tr>
<tr>
<td>Key</td>
<td>Value</td>
</tr>
</tbody>
</table>