Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Fix thead on page scroll

Tags:

jquery

Situation: A page with a table with several rows. I want to fix thead when thead reach the top of the page when scrolling, using jquery or any given scripting. I don't want to overflow the table itself.

like image 621
egidiocs Avatar asked Mar 04 '10 19:03

egidiocs


People also ask

How do I fix a scrolling table header?

By setting postion: sticky and top: 0, we can create a fixed header on a scroll in HTML tables.

How do you freeze the thead in a table?

To freeze the row/column we can use a simple HTML table and CSS. HTML: In HTML we can define the header row by <th> tag or we can use <td> tag also. Below example is using the <th> tag. We also put the table in DIV element to see the horizontal and vertical scrollbar by setting the overflow property of the DIV element.

How do you keep the header static on top when scrolling?

Set padding-top on the <body> element to be the same as the height of your header. This will move your content <div> down, and leave enough space for the header. Set the header <div> to position: absolute; top: 0; to remove it from the normal layout flow, and position it at the top of the page.

How do you make Tbody scrollable?

If you want tbody to show a scrollbar, set its display: block; . Set display: table; for the tr so that it keeps the behavior of a table. To evenly spread the cells, use table-layout: fixed; . Anyhow, to set a scrollbar, a display reset is needed to get rid of the table-layout (which will never show scrollbar).


2 Answers

You can use Lobstrosity's code with a slight modification: position: fixed instead of absolute.

position: fixed is now widely adopted by all browsers including IE8 and onwards. BTW fixed renders much nicer on mobile/tablet devices than position: absolute.

I found that on a table with dynamic widths for each column, the absolutely positioned <thead> would lose the widths of the rest of the columns, so to fix this I came up with the following code:

What this code does is as follows:

Determines the widths of each column in your table by looking up the CSS widths of the first <tbody> <tr> <td> row and storing these in an array for later. When the user scrolls the class 'fixed' is added to the <thead> (Default browser behaviour will alter the widths of the <th>'s and they won't match up with the <tbody>. So to fix this we retroactively set the widths of the <th> to the values we've read earlier.

Anyway here's the code:

CSS

table.entries {width: 100%;border-spacing: 0px;margin:0;}
table.entries thead.fixed {position:fixed;top:0;}

HTML

<table class="entries" id="entriestable">
    <thead>
        <tr>
            <th>Name</th>
            <th>Email</th>
            <th>Location</th>
            <th>DOB</th>
            <th>Opt&nbsp;in</th>
            <th>Added</th>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td class="name">Ricky Bobby</td>
            <td>[email protected]</td>
            <td class="addy"><i>Kent, GB</i></td>
            <td class="dob">20/08/1984</td>
            <td>Yes</td>
            <td class="date">4 hours ago</td>
        </tr>
    </tbody>
</table>

JavaScript

TableThing = function(params) {
    settings = {
        table: $('#entriestable'),
        thead: []
    };

    this.fixThead = function() {
        // empty our array to begin with
        settings.thead = [];
        // loop over the first row of td's in &lt;tbody> and get the widths of individual &lt;td>'s
        $('tbody tr:eq(1) td', settings.table).each( function(i,v){
            settings.thead.push($(v).width());
        });

        // now loop over our array setting the widths we've got to the &lt;th>'s
        for(i=0;i<settings.thead.length;i++) {
            $('thead th:eq('+i+')', settings.table).width(settings.thead[i]);
        }

        // here we attach to the scroll, adding the class 'fixed' to the &lt;thead> 
        $(window).scroll(function() {
            var windowTop = $(window).scrollTop();

            if (windowTop > settings.table.offset().top) {
                $("thead", settings.table).addClass("fixed");
            }
            else {
                $("thead", settings.table).removeClass("fixed");
            }
        });
    }
}
$(function(){
    var table = new TableThing();
    table.fixThead();
    $(window).resize(function(){
        table.fixThead();
    });
});
like image 89
James Thatcher Avatar answered Oct 24 '22 04:10

James Thatcher


Here's something that kind of works (quickly tested in FF 3.5, Chrome 3, and IE 8) that you might be able to tailor to your needs.

It uses absolute positioning of the thead. When the thead becomes absolutely positioned, this basically removes it from the original flow of the table and the widths of all the tbody tds adjust accordingly. So you get ugly behavior if you don't specify column widths or if any column's header is wider than any other cell in that column.

CSS

#Grid thead.Fixed
{
    position: absolute;
}

HTML

<table id="Grid">
    <thead>
        <tr>
            <td>A</td>
            <td>B</td>
            <td>C</td>
        </tr>
    </thead>
    <tbody>
        <tr>
            <td>1</td>
            <td>2</td>
            <td>3</td>
        </tr>
        <!-- etc. -->
    </tbody>
</table>

jQuery

$(function() {
    var table = $("#Grid");

    $(window).scroll(function() {
        var windowTop = $(window).scrollTop();

        if (windowTop > table.offset().top) {
            $("thead", table).addClass("Fixed").css("top", windowTop);
        }
        else {
            $("thead", table).removeClass("Fixed");
        }
    });
});

I noticed that it does not work in IE unless you specify a strict XHTML doctype:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <!-- etc. -->
like image 24
Lobstrosity Avatar answered Oct 24 '22 03:10

Lobstrosity