带有固定表头和水平滚动条的表格

10
我希望有一个带有固定标题和水平滚动的表格。
我不想在表格内部垂直滚动,它应该随页面一起滚动。所以不设置表的高度。 这个可能吗?
这是一个不起作用示例的codepen: https://codepen.io/fwitkowski/pen/zYEQvvg 当我从table-container中移除overflow:auto时,position:sticky就能正常工作。
.table-container {
  max-width:350px;
  overflow-x:auto; /* for horizontal scroll */
  position: relative; /* relative to the normal flow */
  border: solid 5px red /* for reference */
}
2个回答

15
根据MDN文档的说明:
一个sticky元素会“粘”在最近具有“滚动机制”的祖先元素上(当overflowhiddenscrollautooverlay时创建),即使该祖先元素不是实际滚动的祖先元素。 W3C存储库上有一个活跃的GitHub问题,该问题自2017年以来一直存在。已经提出了各种解决方法,但它们似乎都依赖于向表格/表格容器添加固定高度,或者像这个答案中使用Javascript
至少目前,这不是原生支持的功能。

我认为这是正确的(不幸的是),我将选择最大高度,并为表格容器(X和Y)同时添加滚动条。 - Filip Witkowski
有没有JS的解决方案可以绕过这个问题?如果没有,那就太疯狂了! - Dan
@Dan,我在我的回答中链接了一个。 :) - Richard Deeming

1
使用position:sticky的表头希望固定在其父元素(表格)的顶部,而不是窗口,因为表格具有overflow-x:scroll。我想出了一个简单的解决方法,不依赖于固定高度或自定义滚动条,只使用了JavaScript。
这个技巧是将表格分成两个表格。一个是表头表格(tableHeaders),一个是主体表格(tableBody)。tableHeaders具有overflow-x:hidden,而tableBody具有overflow-x:scroll。现在,表头不再在表格内部,主体可以滚动。唯一的问题是表头不会滚动,但我们可以通过使用onscroll事件将其与tableBody的滚动匹配来轻松解决。
将这两个表格都包裹在一个div中,以使粘性效果在表体结束。
最后一件事是确保tableHeaders中的列宽与tableBody的表头生成的列宽相匹配。我们可以用一点点的JavaScript来处理这个问题。在内容加载后的某个地方调用它即可。
// The FullHeightTable component is expected to build a Sticky Table containing only an exact copy of the Primary Tables headers.
// The Sticky Table should be placed above the Primary Table.
function FixFullHeightTable() {

    // Select Primary Table body with built in headers.
    var tBody = document.getElementById('tableBody');
    var thead = tBody.querySelector('thead');

    // Select Sticky Table with only headers. This table contains only a copy of the Primary Table headers with no body. 
    // It is placed directly above the Primary Table and is intended to replace the Primary Table built in headers.
    // It's purpose is to stick to the top of the screen outside of the table markup.
    var stickyThead = document.getElementById('tableHeaders').querySelector('thead');
    var stickycolumns = stickyThead.querySelectorAll('th');


    // Copy the column widths from our hidden Primary table header to our Sticky Table header.
    var ths = thead.querySelectorAll('th');
    for (var i = 0; i < ths.length; i++) {
        var th = ths[i];
        // Since the Sticky Table header is expected to be an exact copy of the Primary Table, we know their indicies will be the same.
        stickycolumns[i].style.minWidth = th.offsetWidth + 'px';
        stickycolumns[i].style.maxWidth = th.offsetWidth + 'px';
    }

    // Sometimes setting line-height and opacity won't be enough to collapse the header to 0px.
    // We'll cover those edge cases by moving the table body over the header.
    // Warning: We can't remove Primary table header because they determine some of our column formatting, especially when css is involved.
    tBody.style.marginTop = `-${thead.offsetHeight}px`;
}

注意:我在Blazor环境中工作,所有内容都包装在一个组件中,其中<thead>作为RenderFragment传递,并自动复制。如果是其他情况,我可能会使用JavaScript将标题克隆到一个粘性表格中,而不是在标记中添加混乱的内容。

警告:如果页面上还有其他粘性或固定元素,则顶部应与它们的高度相等。我还有另一个示例,展示了如何自动处理这个问题。

<div>
    <div id="tableHeaders" style="overflow-x:hidden;position:sticky;top:0; background: red;color: white;">
    <table >
        <thead>
            <tr>
                <th style="white-space: nowrap !important">1. A Very Long Header That Never Ends</th>
                <th style="white-space: nowrap !important">2. A Very Long Header That Never Ends</th>
                <th style="white-space: nowrap !important">3. A Very Long Header That Never Ends</th>
                <th style="white-space: nowrap !important">4. A Very Long Header That Never Ends</th>
                <th style="white-space: nowrap !important">5. A Very Long Header That Never Ends</th>
                    <th style="white-space: nowrap !important">6. A Very Long Header That Never Ends</th>
            </tr>
        </thead>
    </table>
    </div>

    <div id="tableBody" style="overflow-x:scroll" onscroll="document.getElementById('tableHeaders').scrollLeft = this.scrollLeft">
    <table>
            <thead style="line-height:0px;opacity:0">
            <tr>
                <th style="white-space: nowrap !important">1. A Very Long Header That Never Ends</th>
                <th style="white-space: nowrap !important">2. A Very Long Header That Never Ends</th>
                <th style="white-space: nowrap !important">3. A Very Long Header That Never Ends</th>
                <th style="white-space: nowrap !important">4. A Very Long Header That Never Ends</th>
                <th style="white-space: nowrap !important">5. A Very Long Header That Never Ends</th>
                <th style="white-space: nowrap !important">6. A Very Long Header That Never Ends</th>
            </tr>
        </thead>
        <tbody>
            <tr>
                <td style="white-space: nowrap !important" >1. This is some very long content</td>
                <td style="white-space: nowrap !important" >2. This is some very long content</td>
                <td style="white-space: nowrap !important" >3. This is some very long content</td>
                <td style="white-space: nowrap !important" >4. This is some very long content</td>
                <td style="white-space: nowrap !important" >5. This is some very long content</td>
                <td style="white-space: nowrap !important" >6. This is some very long content</td>
            </tr>
            <tr>
                <td style="white-space: nowrap !important" >1. This is some very long content</td>
                <td style="white-space: nowrap !important" >2. This is some very long content</td>
                <td style="white-space: nowrap !important" >3. This is some very long content</td>
                <td style="white-space: nowrap !important" >4. This is some very long content</td>
                <td style="white-space: nowrap !important" >5. This is some very long content</td>
                <td style="white-space: nowrap !important" >6. This is some very long content</td>
            </tr>
            <tr>
                <td style="white-space: nowrap !important" >1. This is some very long content</td>
                <td style="white-space: nowrap !important" >2. This is some very long content</td>
                <td style="white-space: nowrap !important" >3. This is some very long content</td>
                <td style="white-space: nowrap !important" >4. This is some very long content</td>
                <td style="white-space: nowrap !important" >5. This is some very long content</td>
                <td style="white-space: nowrap !important" >6. This is some very long content</td>
            </tr>
            <tr>
                <td style="white-space: nowrap !important" >1. This is some very long content</td>
                <td style="white-space: nowrap !important" >2. This is some very long content</td>
                <td style="white-space: nowrap !important" >3. This is some very long content</td>
                <td style="white-space: nowrap !important" >4. This is some very long content</td>
                <td style="white-space: nowrap !important" >5. This is some very long content</td>
                <td style="white-space: nowrap !important" >6. This is some very long content</td>
            </tr>
            <tr>
                <td style="white-space: nowrap !important" >1. This is some very long content</td>
                <td style="white-space: nowrap !important" >2. This is some very long content</td>
                <td style="white-space: nowrap !important" >3. This is some very long content</td>
                <td style="white-space: nowrap !important" >4. This is some very long content</td>
                <td style="white-space: nowrap !important" >5. This is some very long content</td>
                <td style="white-space: nowrap !important" >6. This is some very long content</td>
            </tr>
            <tr>
                <td style="white-space: nowrap !important" >1. This is some very long content</td>
                <td style="white-space: nowrap !important" >2. This is some very long content</td>
                <td style="white-space: nowrap !important" >3. This is some very long content</td>
                <td style="white-space: nowrap !important" >4. This is some very long content</td>
                <td style="white-space: nowrap !important" >5. This is some very long content</td>
                <td style="white-space: nowrap !important" >6. This is some very long content</td>
            </tr>
        </tbody>
    </table>
    </div>

</div>


<div style="min-height:2000px">
 <p> Just some long body content</p>
</div>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接