具有固定列和标题的可滚动表格,带有现代 CSS
Posted
技术标签:
【中文标题】具有固定列和标题的可滚动表格,带有现代 CSS【英文标题】:Scrollable table with fixed columns and header, with modern CSS 【发布时间】:2018-02-26 18:28:58 【问题描述】:如何使用现代 CSS 制作尽可能少的 javascript 表格?
我想要的功能是:
固定列(定位和宽度) 可在 X 和 Y 轴上滚动 在 X 轴上响应(对于非固定宽度的列)。注意:我确实看到并分析了 SO 中一些最受欢迎/看到的问题和答案,例如 here 和 here。
我知道这可以通过 JavaScript 滚动事件处理程序来完成,以便可以向下/向上移动固定列以跟随主列。我正在尝试构建的功能示例(但编写了大量脚本)could be like this。我们还可以在表的父元素中添加MutationObserver
,以检测大小变化并再次计算表的大小。但这在性能上很昂贵,而且由于 CSS 也在不断发展和现代化,我想知道是否有新的方法......
是否有 2017/2018 解决方案仅使用 CSS 或尽可能少的 JS 开销?
我希望避免实现像这样容易崩溃的 JavaScript 解决方案:
我的想法:
a)
:在固定列中使用position: fixed;
问题:
<td>
元素高度必须由 JavaScript 定义或计算。
需要一个滚动事件侦听器,我们需要以编程方式滚动固定列
b)
:使用 div(s) 来“伪造”左列并在表格中显示可滚动的内容
问题:
div 高度必须与表格行高度同步 html 语义丢失,因为固定的“假”列不再是表格语法c)
:使用 N 个表格只显示每个表格的一部分,这样我就可以有 HTML 标记,但保持固定的标题/列。
问题:
重复的 HTML x N 还必须使用 JavaScript 同步大小和滚动使用滚动事件监听器和固定的左列,我们可以像这样使用 JavaScript:
const firstColumn = [...document.querySelectorAll('table tr > *:first-of-type')];
const tableContainer = document.querySelector('.table-container');
tableContainer.addEventListener('scroll', function()
const currentScrollPosition = this.scrollTop * -1;
firstColumn.forEach(el => el.style.marginTop = currentScrollPosition + 'px');
);
.table-container
width: 600px;
height: 300px;
overflow-x: scroll;
overflow-y: scroll;
.table-scroller
width: 1000px;
table
width: 100%;
margin-left: -13px;
table-layout: fixed;
border-collapse: collapse;
border: none;
table th,
table td
padding: 0.8em;
border: 1px solid;
background-color: #eeeeef;
table th
background-color: #6699FF;
font-weight: bold;
table tr
height: 60px;
vertical-align: middle;
table tr > *:first-of-type
position: fixed;
width: 50px;
margin-left: 13px;
margin-top: 0;
height: inherit;
<div class="table-container">
<div class="table-scroller">
<table>
<tbody>
<tr>
<td>Edrward 0</td>
<td>32</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td>London Park no. 0</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 1</td>
<td>32</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td>London Park no. 1</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 2</td>
<td>32</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td>London Park no. 2</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 3</td>
<td>32</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td>London Park no. 3</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 4</td>
<td>32</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td>London Park no. 4</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 5</td>
<td>32</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td>London Park no. 5</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 6</td>
<td>32</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td>London Park no. 6</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 7</td>
<td>32</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td>London Park no. 7</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 8</td>
<td>32</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td>London Park no. 8</td>
<td><a href="#">action</a></td>
</tr>
<tr>
<td>Edrward 9</td>
<td>32</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td>London Park no. 9</td>
<td><a href="#">action</a></td>
</tr>
</tbody>
</table>
</div>
</div>
但是我可以不使用 JavaScript 吗?
关于可能的重复建议:
我的问题中提到了可能的重复项,但它没有我要查找的内容。该问题要求“只冻结一个左列” - 这个问题的范围更广泛,它与固定标题、固定列和可滚动正文有关。 另一个问题和接受的答案来自 2009 年!我认为这个话题,我的具体范围和例子值得重新审视。另外:我的“JS 解决方案”只是 JS 如何破坏的一个示例,我正在寻找现代 CSS 技术来做到这一点。
【问题讨论】:
您只想要一个表格,还是可以接受嵌套元素? @klenium 我没有任何愿望,我的想法是让 CSS 进行滚动、调整大小和响应。也许我们还没有 CSS,我们可能需要 JavaScript。如果您有想法,请分享。我命名的问题和链接是一些单表,一些多表。但它们有一些限制和开销,可能在 2018 年我们不再需要 (?)。 您的 JS “解决方案”并不完美,在主页滚动时会中断 how do I create an HTML table with fixed/frozen left column and scrollable body?的可能重复 @ZachSaucier 在我的问题中提到了可能的重复项,但它没有我要查找的内容。该问题要求“只冻结一个左列” - 这个问题的范围更广泛,它与固定标题、固定列s 和可滚动正文有关.另一个问题和接受的答案来自 2009 年!我认为这个话题,我的具体范围和例子值得重新审视。另外:我的“JS 解决方案”只是 JS 如何破坏的一个示例,我正在寻找现代 CSS 技术来做到这一点。 【参考方案1】:也许您可以尝试使用最近的position:sticky
来实现它。或者,至少,用更少的 javascript 开始方法。
div
overflow:auto;
width:100%;
height:200px;
td,
th
border: 1px solid #000;
width: 100px;
th background-color:red;
table
table-layout: fixed;
width:100%;
td:first-child, th:first-child
position:sticky;
left:0;
z-index:1;
background-color:grey;
td:last-child, th:last-child
position:sticky;
right:0;
z-index:1;
background-color:blue;
thead tr th
position:sticky;
top:0;
th:first-child, th:last-child z-index:2;background-color:red;
<div>
<table>
<thead>
<tr>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
<tr>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
<td> </td>
</tr>
</tbody>
</table>
</div>
【讨论】:
固定高度是不行的,它应该是桌子所在容器的 100% 高度 添加了固定高度以显示示例中的sticky header,使其尽可能接近提供的gif... 对于那些不知道(就像我不知道)的人,您可以将table-layout: fixed
更改为table-layout: auto
以允许您的列宽自动调整大小。这可能会减慢在非常大的表上渲染的速度,因为浏览器需要等待整个表加载后才能确定正确的列大小。
太棒了。非常紧凑且可读的代码支持一个健壮的示例。
如果有人感兴趣,这里有一支 Codepen Pen。 codepen.io/kavinda1995/pen/OJbXxGw【参考方案2】:
只要看看我的代码有一个固定的标题并修复第一列。
<style type="text/css">
.table
font-family: arial, sans-serif;
border-collapse: collapse;
.th
width: 126px;
height: 56px;
padding: 0px 16px;
text-align: left;
background-color: #fafafa;
.td
width: 118px;
min-width: 118px;
max-width: 118px;
height: 56px;
max-height: 56px;
overflow: hidden;
text-align: center;
border-bottom: 2px solid #dddddd;
.pink_color
background-color: pink;
.table_wrapper
position: relative;
.table_scroll
height: 73vh;
overflow: auto;
.table_wrapper table
width: 100%;
.table_wrapper table thead th .text
position: absolute;
z-index: 2;
.tableFixHead
overflow: auto; height: 63vh;
.tableFixHead thead th
position: sticky; top: 0; z-index: 1;
@media only screen and (min-width: 1440px)
.table_scroll
height: 77vh;
overflow: auto;
</style>
<div style="padding-top: 16px;">
<div class="table_wrapper">
<div class="tableFixHead">
<table class="table">
<thead>
<th style="position: sticky; left: 0; z-index: 3;" class="text th"></th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
<th class="text th">1</th>
</thead>
<tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr>
<tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr>
<tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr><tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr><tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr><tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr><tr>
<td style="position: sticky; left: 0; z-index: 2; background: #fafafa;" class="td">test</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
<td class="td">test1</td>
</tr>
</table>
</div>
</div>
</div>
【讨论】:
以上是关于具有固定列和标题的可滚动表格,带有现代 CSS的主要内容,如果未能解决你的问题,请参考以下文章