开发者

Fix thead on page scroll

Situation: A page wi开发者_C百科th 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.


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>ricky.bobby@email.com</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();
    });
});


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. -->


(function ($) {
    $.fn.fixedHeader = function () {
        return this.filter('table').each(function () {
            var that = this;
            var $head = $('<div></div>').addClass('head');
            $(this).before($head);
            $('th', this).each(function () {
                var $el = $(this);
                var $div = $('<div></div>').width($el.outerWidth()).text(
                $el.text());
                $head.append($div);
            });
            $(window).on('scroll', function () {
                var $that = $(that);
                var w = $(window).scrollTop();
                var o = $('th', that).first().offset().top;
                var tableO = $that.offset().top + $that.height();
                if (o < w && tableO > w) {
                    $head.show();
                } else {
                    $head.hide();
                }
            });
        });
    };
})(jQuery);

You can use this jquery plugin (you need to adapt .head style to your thead style). Working example here: http://jsfiddle.net/lukasi/7K52p/1/


Much easier solution in 2020:

The CSS position: sticky now has pretty good browser support.

See: https://caniuse.com/#feat=css-sticky

You can't apply position: sticky to either <thead> or <tr>.

But you can make a <thead> sticky by applying the following CSS to <th>:

th {
  position: sticky;
  top: 0;
}

Working Example:

.tableContainer {
  width: 360px;
  border: 1px solid rgb(127, 127, 127);
  max-height: 180px;
  overflow: auto;
}

table {
  width: 100%;
}

th {
  position: sticky;
  top: 4px;
  background-color: rgb(255, 255, 0);
  outline: 2px solid rgb(255, 255, 255);
  transform: translateY(-2px);
}

td {
  width: 60px;
  height: 60px;
}

tr,
td {
  border: 1px solid rgb(191, 191, 191);
  border-collapse: collapse;
}

tr:nth-of-type(odd) td:nth-of-type(odd),
tr:nth-of-type(even) td:nth-of-type(even) {
  background-color: rgb(0, 0, 0);
}
<div class="tableContainer">

<table>
<thead>
<tr>
<th>This</th>
<th>thead</th>
<th>is</th>
<th>now</th>
<th>sticky</th>
</tr>
</thead>

<tbody>
<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>

<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>


<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>


<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>


<tr>
<td></td>
<td></td>
<td></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>

</div>

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜