60

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 and TBODY 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;
}
Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746
  • Related: http://stackoverflow.com/questions/33075195/how-to-get-the-header-out-of-the-scroll-area – AlikElzin-kilaka Oct 22 '15 at 10:32
  • 1
    IMHO you need to add a constrain to the question: How to scroll table's “tbody” independent of “thead” respecting the alignment of columns of thead and tbody? – willy wonka May 13 '18 at 09:56

5 Answers5

48

The missing part is:

thead, tbody {
    display: block;
}

Demo

Misha Moroshko
  • 166,356
  • 226
  • 505
  • 746
bookcasey
  • 39,223
  • 13
  • 77
  • 94
  • 3
    what's the downside of changing the display of the table head/body from "table" to block ? – kdubs Dec 12 '12 at 15:55
  • 8
    @kdubs It certainly breaks stuff. Just have a look here [in this jsbin first differences are visible straight on](http://jsbin.com/oyoyov/3/edit) so basically some of the table specific properties just break. This solution is imho a hack. – Toskan Jan 14 '13 at 10:58
  • I guess I should have just tried it myself, but yes, that looks a bit ugly – kdubs Jan 14 '13 at 12:30
  • 3
    With this method colspan becomes unusable – Yacine Zalouani Feb 12 '13 at 14:17
  • 19
    Yeah, if you add a couple columns it's obvious they're no longer aligned: http://jsfiddle.net/nyCKE/2136/ –  Sep 12 '13 at 21:21
  • 1
    Not working when `height: 100%` (when you want the table to expand to the bottom of the page). – AlikElzin-kilaka Oct 22 '15 at 10:26
  • Does not work when the table does not have a fixed, specified, height; which is 100% of the time. – Ian Boyd Jun 30 '19 at 14:30
  • Sorry but if you just add the css rule td, th { border: solid black 1px; } you will notice that this is not the right solution because columns and respective headers are miss aligned because of the vertical scrollbar width. Have a look: jsfiddle.net/d8pxaumn . So try to use thead * { position: sticky; } instead, with some further fine tuning. The table / column layout also brakes even if text in tbody td is longer than th text content – willy wonka Aug 01 '19 at 10:58
2

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.

Borgboy
  • 640
  • 5
  • 6
  • Is there any difference between `.find("> thead, tfoot")` and `.children("thead, tfoot")`? – matpie Oct 22 '15 at 22:39
  • SirLanceLot: In this particular case there is no functional difference given the ">" in the find selector. It probably makes for better performance to use `.children("thead, tfoot"). – Borgboy Oct 23 '15 at 14:06
1

try this.

table 
{
    background-color: #aaa;
}

tbody 
{
    background-color: #ddd;
    height: 100px;
    overflow-y: scroll;
    position: absolute;
}

td 
{
    padding: 3px 10px;
    color: green;
    width: 100px;
}
Bhimbim
  • 1,348
  • 2
  • 19
  • 15
  • This worked really well for me, but I had to make a few changes - namely I had to set the width of each td as a percentage of the row width and set the td display to "table". – Tyler Aug 05 '18 at 03:14
0
thead {
  position: fixed;
  height: 10px; /* This is whatever height you want */
}
  tbody {
  position: fixed;
  margin-top: 10px; /* This has to match the height of thead */
  height: 300px; /* This is whatever height you want */
}
Community
  • 1
  • 1
John K. Chow
  • 1,651
  • 16
  • 24
-1

mandatory parts:

tbody {
    overflow-y: scroll;  (could be: 'overflow: scroll' for the two axes)
    display: block;
    with: xxx (a number or 100%)
}

thead {
    display: inline-block;
}
freignat
  • 57
  • 4