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

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


当前回答

所有从CSS规范之外解决这个问题的尝试都是我们真正想要的:按照THEAD的隐含承诺交付。

这个冻结表头的问题长期以来一直是HTML/CSS中的一个开放性问题。

在理想的情况下,应该有一个纯css解决方案来解决这个问题。不幸的是,似乎没有一个合适的。

相关标准-关于此主题的讨论包括:

粘性定位提案网址:http://lists.w3.org/Archives/Public/www-style/2012Jun/0627.html 请在阿特金斯提出的“位置-根”、“位置-包含”或“位置-限制”的建议中打上标签:http://www.xanthir.com/blog/b48H0

更新:Firefox的发货位置:粘在版本32。每个人都会赢!

其他回答

这不是固定标题行的精确解决方案,但我创建了一种相当巧妙的方法,在整个长表中重复标题行,但仍然保持排序能力。

这个简洁的小选项需要jQuery tablesorter插件。下面是它的工作原理:

HTML

<table class="tablesorter boxlist" id="pmtable">
    <thead class="fixedheader">
        <tr class="boxheadrow">
            <th width="70px" class="header">Job Number</th>
            <th width="10px" class="header">Pri</th>
            <th width="70px" class="header">CLLI</th>
            <th width="35px" class="header">Market</th>
            <th width="35px" class="header">Job Status</th>
            <th width="65px" class="header">Technology</th>
            <th width="95px;" class="header headerSortDown">MEI</th>
            <th width="95px" class="header">TEO Writer</th>
            <th width="75px" class="header">Quote Due</th>
            <th width="100px" class="header">Engineer</th>
            <th width="75px" class="header">ML Due</th>
            <th width="75px" class="header">ML Complete</th>
            <th width="75px" class="header">SPEC Due</th>
            <th width="75px" class="header">SPEC Complete</th>
            <th width="100px" class="header">Install Supervisor</th>
            <th width="75px" class="header">MasTec OJD</th>
            <th width="75px" class="header">Install Start</th>
            <th width="30px" class="header">Install Hours</th>
            <th width="75px" class="header">Revised CRCD</th>
            <th width="75px" class="header">Latest Ship-To-Site</th>
            <th width="30px" class="header">Total Parts</th>
            <th width="30px" class="header">OEM Rcvd</th>
            <th width="30px" class="header">Minor Rcvd</th>
            <th width="30px" class="header">Total Received</th>
            <th width="30px" class="header">% On Site</th>
            <th width="60px" class="header">Actions</th>
        </tr>
    </thead>
        <tbody class="scrollable">
            <tr data-job_id="3548" data-ml_id="" class="odd">
                <td class="c black">FL-8-RG9UP</td>
                <td data-pri="2" class="priority c yellow">M</td>
                <td class="c">FTLDFLOV</td>
                <td class="c">SFL</td>
                <td class="c">NOI</td>
                <td class="c">TRANSPORT</td>
                <td class="c"></td>
                <td class="c">Chris Byrd</td>
                <td class="c">Apr 13, 2013</td>
                <td class="c">Kris Hall</td>
                <td class="c">May 20, 2013</td>
                <td class="c">May 20, 2013</td>
                <td class="c">Jun 5, 2013</td>
                <td class="c">Jun 7, 2013</td>
                <td class="c">Joseph Fitz</td>
                <td class="c">Jun 10, 2013</td>
                <td class="c">TBD</td>
                <td class="c">123</td>
                <td class="c revised_crcd"><input readonly="true" name="revised_crcd" value="Jul 26, 2013" type="text" size="12" class="smInput r_crcd c hasDatepicker" id="dp1377194058616"></td>
                <td class="c">TBD</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="c">N/A</td>
                <td class="actions"><span style="float:left;" class="ui-icon ui-icon-folder-open editJob" title="View this job" s="" details'=""></span></td>
            </tr>
            <tr data-job_id="4264" data-ml_id="2959" class="even">
                <td class="c black">MTS13009SF</td>
                <td data-pri="2" class="priority c yellow">M</td>
                <td class="c">OJUSFLTL</td>
                <td class="c">SFL</td>
                <td class="c">NOI</td>
                <td class="c">TRANSPORT</td>
                <td class="c"></td>
                <td class="c">DeMarcus Stewart</td>
                <td class="c">May 22, 2013</td>
                <td class="c">Ryan Alsobrook</td>
                <td class="c">Jun 19, 2013</td>
                <td class="c">Jun 27, 2013</td>
                <td class="c">Jun 19, 2013</td>
                <td class="c">Jul 4, 2013</td>
                <td class="c">Randy Williams</td>
                <td class="c">Jun 21, 2013</td>
                <td class="c">TBD</td>
                <td class="c">95</td>
                <td class="c revised_crcd"><input readonly="true" name="revised_crcd" value="Aug 9, 2013" type="text" size="12" class="smInput r_crcd c hasDatepicker" id="dp1377194058632"></td><td class="c">TBD</td>
                <td class="c">0</td>
                <td class="c">0.00%</td>
                <td class="c">0.00%</td>
                <td class="c">0.00%</td>
                <td class="c">0.00%</td>
                <td class="actions"><span style="float:left;" class="ui-icon ui-icon-folder-open editJob" title="View this job" s="" details'=""></span><input style="float:left;" type="hidden" name="req_ship" class="reqShip hasDatepicker" id="dp1377194058464"><span style="float:left;" class="ui-icon ui-icon-calendar requestShip" title="Schedule this job for shipping"></span><span class="ui-icon ui-icon-info viewOrderInfo" style="float:left;" title="Show material details for this order"></span></td>
            </tr>
            .
            .
            .
            .
            <tr class="boxheadrow repeated-header">
                <th width="70px" class="header">Job Number</th>
                <th width="10px" class="header">Pri</th>
                <th width="70px" class="header">CLLI</th>
                <th width="35px" class="header">Market</th>
                <th width="35px" class="header">Job Status</th>
                <th width="65px" class="header">Technology</th>
                <th width="95px;" class="header">MEI</th>
                <th width="95px" class="header">TEO Writer</th>
                <th width="75px" class="header">Quote Due</th>
                <th width="100px" class="header">Engineer</th>
                <th width="75px" class="header">ML Due</th>
                <th width="75px" class="header">ML Complete</th>
                <th width="75px" class="header">SPEC Due</th>
                <th width="75px" class="header">SPEC Complete</th>
                <th width="100px" class="header">Install Supervisor</th>
                <th width="75px" class="header">MasTec OJD</th>
                <th width="75px" class="header">Install Start</th>
                <th width="30px" class="header">Install Hours</th>
                <th width="75px" class="header">Revised CRCD</th>
                <th width="75px" class="header">Latest Ship-To-Site</th>
                <th width="30px" class="header">Total Parts</th>
                <th width="30px" class="header">OEM Rcvd</th>
                <th width="30px" class="header">Minor Rcvd</th>
                <th width="30px" class="header">Total Received</th>
                <th width="30px" class="header">% On Site</th>
                <th width="60px" class="header">Actions</th>
            </tr>

显然,我的表的行要比这个多很多。确切地说是193,但是你可以看到标题行重复的地方。重复的标题行是由这个函数建立的:

jQuery

// Clone the original header row and add the "repeated-header" class
var tblHeader = $('tr.boxheadrow').clone().addClass('repeated-header');

// Add the cloned header with the new class every 34th row (or as you see fit)
$('tbody tr:odd:nth-of-type(17n)').after(tblHeader);

// On the 'sortStart' routine, remove all the inserted header rows
$('#pmtable').bind('sortStart', function() {
    $('.repeated-header').remove();
    // On the 'sortEnd' routine, add back all the header row lines.
}).bind('sortEnd', function() {
    $('tbody tr:odd:nth-of-type(17n)').after(tblHeader);
});

我一直在寻找一个解决方案,发现大多数答案都不工作或不适合我的情况,所以我用jQuery编写了一个简单的解决方案。

这是解决方案大纲:

克隆需要固定表头的表,并放置 在原拷贝之上的克隆拷贝。 从主表上拆下表体。 从底部表中删除表头。 调整列的宽度。(我们跟踪原始列的宽度)

下面是一个可运行的演示代码。

function scrolify(tblAsJQueryObject, height) { var oTbl = tblAsJQueryObject; // for very large tables you can remove the four lines below // and wrap the table with <div> in the mark-up and assign // height and overflow property var oTblDiv = $("<div/>"); oTblDiv.css('height', height); oTblDiv.css('overflow', 'scroll'); oTbl.wrap(oTblDiv); // save original width oTbl.attr("data-item-original-width", oTbl.width()); oTbl.find('thead tr td').each(function() { $(this).attr("data-item-original-width", $(this).width()); }); oTbl.find('tbody tr:eq(0) td').each(function() { $(this).attr("data-item-original-width", $(this).width()); }); // clone the original table var newTbl = oTbl.clone(); // remove table header from original table oTbl.find('thead tr').remove(); // remove table body from new table newTbl.find('tbody tr').remove(); oTbl.parent().parent().prepend(newTbl); newTbl.wrap("<div/>"); // replace ORIGINAL COLUMN width newTbl.width(newTbl.attr('data-item-original-width')); newTbl.find('thead tr td').each(function() { $(this).width($(this).attr("data-item-original-width")); }); oTbl.width(oTbl.attr('data-item-original-width')); oTbl.find('tbody tr:eq(0) td').each(function() { $(this).width($(this).attr("data-item-original-width")); }); } $(document).ready(function() { scrolify($('#tblNeedsScrolling'), 160); // 160 is height }); <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.6.4/jquery.min.js"></script> <div style="width:300px;border:6px green solid;"> <table border="1" width="100%" id="tblNeedsScrolling"> <thead> <tr><th>Header 1</th><th>Header 2</th></tr> </thead> <tbody> <tr><td>row 1, cell 1</td><td>row 1, cell 2</td></tr> <tr><td>row 2, cell 1</td><td>row 2, cell 2</td></tr> <tr><td>row 3, cell 1</td><td>row 3, cell 2</td></tr> <tr><td>row 4, cell 1</td><td>row 4, cell 2</td></tr> <tr><td>row 5, cell 1</td><td>row 5, cell 2</td></tr> <tr><td>row 6, cell 1</td><td>row 6, cell 2</td></tr> <tr><td>row 7, cell 1</td><td>row 7, cell 2</td></tr> <tr><td>row 8, cell 1</td><td>row 8, cell 2</td></tr> </tbody> </table> </div>

该解决方案支持Chrome和IE浏览器。因为它是基于jQuery的,所以在其他jQuery支持的浏览器中也能正常工作。

我刚刚完成了一个jQuery插件,将采取有效的单一表使用有效的HTML(必须有一个标题和tbody),并将输出一个表,有固定的标题,可选的固定页脚,可以是一个克隆的标题或任何你选择的内容(分页等)。如果你想利用更大的显示器,它也会在浏览器调整大小时调整表的大小。另一个添加的特性是,如果表列不能全部放入视图,则可以侧滚动。

http://fixedheadertable.com/

在github: http://markmalek.github.com/Fixed-Header-Table/

它非常容易安装,你可以为它创建自己的自定义样式。它还在所有浏览器中使用圆角。请记住,我刚刚发布了它,所以它在技术上仍然是测试版,有一些小问题我正在解决。

它适用于Internet Explorer 7、Internet Explorer 8、Safari、Firefox和Chrome浏览器。

博士TL;

如果您的目标是现代浏览器,并且没有奢侈的样式需求:http://jsfiddle.net/dPixie/byB9d/3/…虽然四大版本是相当甜蜜的以及这个版本处理流体宽度好得多。

大家好!

随着HTML5和CSS3的进步,至少对于现代浏览器来说,这是可能的。我提出的稍微有点粗糙的实现可以在这里找到:http://jsfiddle.net/dPixie/byB9d/3/。我已经在FX 25, Chrome 31和IE 10上测试过了…

相关的HTML(在你的文档顶部插入一个HTML5文档类型):

html, body { margin: 0; padding: 0; height: 100%; } section { position: relative; border: 1px solid #000; padding-top: 37px; background: #500; } section.positioned { position: absolute; top: 100px; left: 100px; width: 800px; box-shadow: 0 0 15px #333; } .container { overflow-y: auto; height: 200px; } table { border-spacing: 0; width: 100%; } td+td { border-left: 1px solid #eee; } td, th { border-bottom: 1px solid #eee; background: #ddd; color: #000; padding: 10px 25px; } th { height: 0; line-height: 0; padding-top: 0; padding-bottom: 0; color: transparent; border: none; white-space: nowrap; } th div { position: absolute; background: transparent; color: #fff; padding: 9px 25px; top: 0; margin-left: -25px; line-height: normal; border-left: 1px solid #800; } th:first-child div { border: none; } <section class="positioned"> <div class="container"> <table> <thead> <tr class="header"> <th> Table attribute name <div>Table attribute name</div> </th> <th> Value <div>Value</div> </th> <th> Description <div>Description</div> </th> </tr> </thead> <tbody> <tr> <td>align</td> <td>left, center, right</td> <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the alignment of a table according to surrounding text</td> </tr> <tr> <td>bgcolor</td> <td>rgb(x,x,x), #xxxxxx, colorname</td> <td>Not supported in HTML5. Deprecated in HTML 4.01. Specifies the background color for a table</td> </tr> <tr> <td>border</td> <td>1,""</td> <td>Specifies whether the table cells should have borders or not</td> </tr> <tr> <td>cellpadding</td> <td>pixels</td> <td>Not supported in HTML5. Specifies the space between the cell wall and the cell content</td> </tr> <tr> <td>cellspacing</td> <td>pixels</td> <td>Not supported in HTML5. Specifies the space between cells</td> </tr> <tr> <td>frame</td> <td>void, above, below, hsides, lhs, rhs, vsides, box, border</td> <td>Not supported in HTML5. Specifies which parts of the outside borders that should be visible</td> </tr> <tr> <td>rules</td> <td>none, groups, rows, cols, all</td> <td>Not supported in HTML5. Specifies which parts of the inside borders that should be visible</td> </tr> <tr> <td>summary</td> <td>text</td> <td>Not supported in HTML5. Specifies a summary of the content of a table</td> </tr> <tr> <td>width</td> <td>pixels, %</td> <td>Not supported in HTML5. Specifies the width of a table</td> </tr> </tbody> </table> </div> </section>

但是如何? !

简单地说,你有一个表头,你通过使它高0px来隐藏它,它还包含了用作固定表头的div。表的容器在顶部留下了足够的空间来允许绝对定位的标题,并且带有滚动条的表如您所期望的那样出现。

上面的代码使用了定位类来确定表的位置(我在弹出式对话框中使用它),但是您也可以通过从容器中删除定位类来在文档流中使用它。

但是…

它并不完美。Firefox拒绝使标题行为0px(至少我没有找到任何方法),但固执地保持它至少为4px…这不是一个大问题,但取决于你的样式,它会混淆你的边界等。

该表还使用了一种伪列方法,其中容器本身的背景色被用作标题div的背景,这是透明的。

总结

总而言之,根据您的需求,可能会有样式问题,特别是边界或复杂的背景。可计算性可能也有问题,我还没有在各种各样的浏览器中检查它(如果你尝试过,请评论你的经验),但我没有发现任何类似的东西,所以我认为无论如何都值得发布…

几乎所有的现代浏览器都支持它!

// '.tbl-content' consumed little space for vertical scrollbar, scrollbar width depend on browser/os/platfrom. Here calculate the scollbar width . $(window).on("load resize ", function() { var scrollWidth = $('.tbl-content').width() - $('.tbl-content table').width(); $('.tbl-header').css({ 'padding-right': scrollWidth }); }).resize(); h1 { font-size: 30px; color: #fff; text-transform: uppercase; font-weight: 300; text-align: center; margin-bottom: 15px; } table { width: 100%; table-layout: fixed; } .tbl-header { background-color: rgba(255, 255, 255, 0.3); } .tbl-content { height: 300px; overflow-x: auto; margin-top: 0px; border: 1px solid rgba(255, 255, 255, 0.3); } th { padding: 20px 15px; text-align: left; font-weight: 500; font-size: 12px; color: #fff; text-transform: uppercase; } td { padding: 15px; text-align: left; vertical-align: middle; font-weight: 300; font-size: 12px; color: #fff; border-bottom: solid 1px rgba(255, 255, 255, 0.1); } /* demo styles */ @import url(https://fonts.googleapis.com/css?family=Roboto:400,500,300,700); body { background: -webkit-linear-gradient(left, #25c481, #25b7c4); background: linear-gradient(to right, #25c481, #25b7c4); font-family: 'Roboto', sans-serif; } section { margin: 50px; } /* follow me template */ .made-with-love { margin-top: 40px; padding: 10px; clear: left; text-align: center; font-size: 10px; font-family: arial; color: #fff; } .made-with-love i { font-style: normal; color: #F50057; font-size: 14px; position: relative; top: 2px; } .made-with-love a { color: #fff; text-decoration: none; } .made-with-love a:hover { text-decoration: underline; } /* for custom scrollbar for webkit browser*/ ::-webkit-scrollbar { width: 6px; } ::-webkit-scrollbar-track { -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); } ::-webkit-scrollbar-thumb { -webkit-box-shadow: inset 0 0 6px rgba(0, 0, 0, 0.3); } <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script> <section> <!--for demo wrap--> <h1>Fixed Table header</h1> <div class="tbl-header"> <table cellpadding="0" cellspacing="0" border="0"> <thead> <tr> <th>Code</th> <th>Company</th> <th>Price</th> <th>Change</th> <th>Change %</th> </tr> </thead> </table> </div> <div class="tbl-content"> <table cellpadding="0" cellspacing="0" border="0"> <tbody> <tr> <td>AAC</td> <td>AUSTRALIAN COMPANY </td> <td>$1.38</td> <td>+2.01</td> <td>-0.36%</td> </tr> <tr> <td>AAD</td> <td>AUSENCO</td> <td>$2.38</td> <td>-0.01</td> <td>-1.36%</td> </tr> <tr> <td>AAX</td> <td>ADELAIDE</td> <td>$3.22</td> <td>+0.01</td> <td>+1.36%</td> </tr> <tr> <td>XXD</td> <td>ADITYA BIRLA</td> <td>$1.02</td> <td>-1.01</td> <td>+2.36%</td> </tr> <tr> <td>AAC</td> <td>AUSTRALIAN COMPANY </td> <td>$1.38</td> <td>+2.01</td> <td>-0.36%</td> </tr> <tr> <td>AAD</td> <td>AUSENCO</td> <td>$2.38</td> <td>-0.01</td> <td>-1.36%</td> </tr> <tr> <td>AAX</td> <td>ADELAIDE</td> <td>$3.22</td> <td>+0.01</td> <td>+1.36%</td> </tr> <tr> <td>XXD</td> <td>ADITYA BIRLA</td> <td>$1.02</td> <td>-1.01</td> <td>+2.36%</td> </tr> <tr> <td>AAC</td> <td>AUSTRALIAN COMPANY </td> <td>$1.38</td> <td>+2.01</td> <td>-0.36%</td> </tr> <tr> <td>AAD</td> <td>AUSENCO</td> <td>$2.38</td> <td>-0.01</td> <td>-1.36%</td> </tr> <tr> <td>AAX</td> <td>ADELAIDE</td> <td>$3.22</td> <td>+0.01</td> <td>+1.36%</td> </tr> <tr> <td>XXD</td> <td>ADITYA BIRLA</td> <td>$1.02</td> <td>-1.01</td> <td>+2.36%</td> </tr> <tr> <td>AAC</td> <td>AUSTRALIAN COMPANY </td> <td>$1.38</td> <td>+2.01</td> <td>-0.36%</td> </tr> <tr> <td>AAD</td> <td>AUSENCO</td> <td>$2.38</td> <td>-0.01</td> <td>-1.36%</td> </tr> <tr> <td>AAX</td> <td>ADELAIDE</td> <td>$3.22</td> <td>+0.01</td> <td>+1.36%</td> </tr> <tr> <td>XXD</td> <td>ADITYA BIRLA</td> <td>$1.02</td> <td>-1.01</td> <td>+2.36%</td> </tr> <tr> <td>AAC</td> <td>AUSTRALIAN COMPANY </td> <td>$1.38</td> <td>+2.01</td> <td>-0.36%</td> </tr> <tr> <td>AAD</td> <td>AUSENCO</td> <td>$2.38</td> <td>-0.01</td> <td>-1.36%</td> </tr> <tr> <td>AAX</td> <td>ADELAIDE</td> <td>$3.22</td> <td>+0.01</td> <td>+1.36%</td> </tr> <tr> <td>XXD</td> <td>ADITYA BIRLA</td> <td>$1.02</td> <td>-1.01</td> <td>+2.36%</td> </tr> <tr> <td>AAC</td> <td>AUSTRALIAN COMPANY </td> <td>$1.38</td> <td>+2.01</td> <td>-0.36%</td> </tr> <tr> <td>AAD</td> <td>AUSENCO</td> <td>$2.38</td> <td>-0.01</td> <td>-1.36%</td> </tr> <tr> <td>AAX</td> <td>ADELAIDE</td> <td>$3.22</td> <td>+0.01</td> <td>+1.36%</td> </tr> <tr> <td>XXD</td> <td>ADITYA BIRLA</td> <td>$1.02</td> <td>-1.01</td> <td>+2.36%</td> </tr> <tr> <td>AAC</td> <td>AUSTRALIAN COMPANY </td> <td>$1.38</td> <td>+2.01</td> <td>-0.36%</td> </tr> <tr> <td>AAD</td> <td>AUSENCO</td> <td>$2.38</td> <td>-0.01</td> <td>-1.36%</td> </tr> <tr> <td>AAX</td> <td>ADELAIDE</td> <td>$3.22</td> <td>+0.01</td> <td>+1.36%</td> </tr> <tr> <td>XXD</td> <td>ADITYA BIRLA</td> <td>$1.02</td> <td>-1.01</td> <td>+2.36%</td> </tr> <tr> <td>AAC</td> <td>AUSTRALIAN COMPANY </td> <td>$1.38</td> <td>+2.01</td> <td>-0.36%</td> </tr> <tr> <td>AAD</td> <td>AUSENCO</td> <td>$2.38</td> <td>-0.01</td> <td>-1.36%</td> </tr> <tr> <td>AAX</td> <td>ADELAIDE</td> <td>$3.22</td> <td>+0.01</td> <td>+1.36%</td> </tr> <tr> <td>XXD</td> <td>ADITYA BIRLA</td> <td>$1.02</td> <td>-1.01</td> <td>+2.36%</td> </tr> </tbody> </table> </div> </section>