How to scroll table's "tbody" independent of "thead"?
As specified in the W3 specification for Tables:
Table rows may be grouped into a table head, table foot, and one or more table body sections, using the
THEAD
,TFOOT
andTBODY
elements, respectively. This division enables user agents to support scrolling of table bodies independently of the table head and foot.
I created the following example, but it doesn't work.
HTML:
<table>
<thead>
<tr>
<td>Problem</td>
<td>Solution</td>
</tr>
</thead>
<tbody>
</tbody>
</table>
JS:
$(function() {
for (var i = 0; i < 20; i++) {
var a = Math.floor(10 * Math.random());
var b = Math.floor(10 * Math.random());
var row = $("<tr>").append($("<td>").html(a + " + " + b + " ="))
.append($("<td>").html(a + b));
$("tbody").append(row);
}
});
CSS:
table {
background-color: #aaa;
}
tbody {
background-color: #ddd;
height: 100px;
overflow: auto;
}
td {
padding: 3px 10px;
}
The missing part is:
thead, tbody {
display: block;
}
Demo
I saw this post about a month ago when I was having similar problems. I needed y-axis scrolling for a table inside of a ui dialog (yes, you heard me right). I was lucky, in that a working solution presented itself fairly quickly. However, it wasn't long before the solution took on a life of its own, but more on that later.
The problem with just setting the top level elements (thead, tfoot, and tbody) to display block, is that browser synchronization of the column sizes between the various components is quickly lost and everything packs to the smallest permissible size. Setting the widths of the columns seems like the best course of action, but without setting the widths of all the internal table components to match the total of these columns, even with a fixed table layout, there is a slight divergence between the headers and body when a scroll bar is present.
The solution for me was to set all the widths, check if a scroll bar was present, and then take the scaled widths the browser had actually decided on, and copy those to the header and footer adjusting the last column width for the size of the scroll bar. Doing this provides some fluidity to the column widths. If changes to the table's width occur, most major browsers will auto-scale the tbody column widths accordingly. All that's left is to set the header and footer column widths from their respective tbody sizes.
$table.find("> thead,> tfoot").find("> tr:first-child")
.each(function(i,e) {
$(e).children().each(function(i,e) {
if (i != column_scaled_widths.length - 1) {
$(e).width(column_scaled_widths[i] - ($(e).outerWidth() - $(e).width()));
} else {
$(e).width(column_scaled_widths[i] - ($(e).outerWidth() - $(e).width()) + $.position.scrollbarWidth());
}
});
});
This fiddle illustrates these notions: http://jsfiddle.net/borgboyone/gbkbhngq/.
Note that a table wrapper or additional tables are not needed for y-axis scrolling alone. (X-axis scrolling does require a wrapping table.) Synchronization between the column sizes for the body and header will still be lost if the minimum pack size for either the header or body columns is encountered. A mechanism for minimum widths should be provided if resizing is an option or small table widths are expected.
The ultimate culmination from this starting point is fully realized here: http://borgboyone.github.io/jquery-ui-table/
A.