是否有跨浏览器的CSS/JavaScript技术来显示一个长HTML表,使列标题保持固定在屏幕上,而不随表体滚动。想想微软Excel中的“冻结窗格”效果。

我希望能够滚动表的内容,但总是能够在顶部看到列标题。


当前回答

CSS属性position: sticky在大多数现代浏览器中都有很好的支持(我在使用Edge时遇到了问题,见下文)。

这让我们很容易解决固定头文件的问题:

thead th { position: sticky; top: 0; }

Safari需要一个供应商前缀:-webkit-sticky。

对于Firefox,我必须在父元素中添加min-height: 0到1。我忘了为什么要这么做了。

最不幸的是,微软Edge的实现似乎只是半工作。至少,在我的测试中有一些闪烁和不对齐的表单元格。这张桌子仍然可用,但在美学上存在重大问题。

其他回答

我还创建了一个插件来解决这个问题。我的项目- jQuery。floatThead已经存在了4年多,非常成熟。

它不需要外部样式,也不期望您的表以任何特定的方式进行样式化。支持Internet Explorer9+和Firefox/Chrome浏览器。

目前(2018-05):

在GitHub上有405次提交和998个星级


这里的许多(不是全部)答案都是快速的技巧,可能解决了某个人的问题,但并不适用于每一张桌子。

其他一些插件已经很老了,可能在ie浏览器上运行得很好,但在Firefox和Chrome浏览器上就不行了。

很多人似乎都在寻找这个答案。我发现它隐藏在这里的另一个问题的答案:同步两个不同帧的表之间的列宽度,等等

在我尝试过的几十种方法中,这是我发现的唯一一种可靠的方法,可以让你有一个滚动的底部表,头部表具有相同的宽度。

以下是我是如何做到的,首先我改进了上面的jsfiddle来创建这个函数,它在td和th上都可以工作(以防绊倒其他人谁使用th来样式化他们的标题行)。

var setHeaderTableWidth= function (headertableid,basetableid) {
            $("#"+headertableid).width($("#"+basetableid).width());
            $("#"+headertableid+" tr th").each(function (i) {
                $(this).width($($("#"+basetableid+" tr:first td")[i]).width());
            });
            $("#" + headertableid + " tr td").each(function (i) {
                $(this).width($($("#" + basetableid + " tr:first td")[i]).width());
            });
        }

接下来,你需要创建两个表,注意头表应该有一个额外的TD,以便在顶部表中为滚动条留出空间,就像这样:

 <table id="headertable1" class="input-cells table-striped">
        <thead>
            <tr style="background-color:darkgray;color:white;"><th>header1</th><th>header2</th><th>header3</th><th>header4</th><th>header5</th><th>header6</th><th></th></tr>
        </thead>
     </table>
    <div id="resizeToBottom" style="overflow-y:scroll;overflow-x:hidden;">
        <table id="basetable1" class="input-cells table-striped">
            <tbody >
                <tr>
                    <td>testdata</td>
                    <td>2</td>
                    <td>3</td>
                    <td>4</span></td>
                    <td>55555555555555</td>
                    <td>test</td></tr>
            </tbody>
        </table>
    </div>

然后这样做:

        setHeaderTableWidth('headertable1', 'basetable1');
        $(window).resize(function () {
            setHeaderTableWidth('headertable1', 'basetable1');
        });

这是我在Stack Overflow上找到的唯一解决方案,可以解决许多类似的问题,在我所有的情况下都有效。

例如,我尝试了不与durandal工作的jQuery stickytables插件和谷歌代码项目https://code.google.com/p/js-scroll-table-header/issues/detail?id=2

其他涉及克隆表的解决方案性能很差,或者很糟糕,并不是在所有情况下都有效。

没有必要使用这些过于复杂的解决方案。只需像下面的例子一样创建两个表,并像这里描述的那样调用setHeaderTableWidth函数,然后嘣,你就完成了。

如果这对你不起作用,你可能在玩你的CSS box-sizing属性,你需要正确设置它。很容易意外地搞砸你的CSS内容。有很多事情都可能出错,所以要注意/小心。这种方法对我很有效。

两个div,一个用于头,一个用于数据。使数据div可滚动,并使用JavaScript将标题中的列的宽度设置为与数据中的宽度相同。我认为数据列的宽度应该是固定的,而不是动态的。

这可以在四行代码中清晰地解决。

如果您只关心现代浏览器,那么使用CSS转换可以更容易地实现固定标头。听起来很奇怪,但效果很好:

HTML和CSS保持原样。 没有外部JavaScript依赖。 四行代码。 适用于所有配置(表布局:固定等)。

document.getElementById("wrap").addEventListener("scroll", function(){
   var translate = "translate(0,"+this.scrollTop+"px)";
   this.querySelector("thead").style.transform = translate;
});

除了Internet Explorer 8-,对CSS转换的支持广泛可用。

下面是完整的例子供参考:

document.getElementById("wrap").addEventListener("scroll",function(){ var translate = "translate(0,"+this.scrollTop+"px)"; this.querySelector("thead").style.transform = translate; }); /* Your existing container */ #wrap { overflow: auto; height: 400px; } /* CSS for demo */ td { background-color: green; width: 200px; height: 100px; } <div id="wrap"> <table> <thead> <tr> <th>Foo</th> <th>Bar</th> </tr> </thead> <tbody> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> <tr><td></td><td></td></tr> </tbody> </table> </div>

支持固定页脚

我扩展了内森的功能,也支持一个固定的页脚和最大高度。 此外,该函数将设置CSS本身,您只需要支持宽度。

用法:

固定高度:

$('table').scrollableTable({ height: 100 });

最大高度(如果浏览器支持CSS 'max-height'选项):

$('table').scrollableTable({ maxHeight: 100 });

脚本:

jQuery.fn.scrollableTable = function(options) {

    var $originalTable, $headTable, $bodyTable, $footTable, $scrollableDiv, originalWidths;

    // Prepare the separate parts of the table
    $originalTable = $(this);
    $headTable = $originalTable.clone();

    $headTable.find('tbody').remove();
    $headTable.find('tfoot').remove();

    $bodyTable = $originalTable.clone();
    $bodyTable.find('thead').remove();
    $bodyTable.find('tfoot').remove();

    $footTable = $originalTable.clone();
    $footTable.find('thead').remove();
    $footTable.find('tbody').remove();

    // Grab the original column widths and set them in the separate tables
    originalWidths = $originalTable.find('tr:first td').map(function() {
        return $(this).width();
    });

    $.each([$headTable, $bodyTable, $footTable], function(index, $table) {
        $table.find('tr:first td').each(function(i) {
            $(this).width(originalWidths[i]);
        });
    });

    // The div that makes the body table scroll
    $scrollableDiv = $('<div/>').css({
        'overflow-y': 'scroll'
    });

    if(options.height) {
        $scrollableDiv.css({'height': options.height});
    }
    else if(options.maxHeight) {
        $scrollableDiv.css({'max-height': options.maxHeight});
    }

    // Add the new separate tables and remove the original one
    $headTable.insertAfter($originalTable);
    $bodyTable.insertAfter($headTable);
    $footTable.insertAfter($bodyTable);
    $bodyTable.wrap($scrollableDiv);
    $originalTable.remove();
};