良好的旧 <table>
标签是显示表格数据的最语义化的 HTML。 但是我发现很难控制表格的呈现方式,特别是在动态环境中,您可能不知道每个表格单元格中将包含多少内容时,列的宽度也很难控制。 在某些情况下,一列非常宽,而其他列则被压缩在一起。 有时,我们会得到相等的宽度,但以牺牲包含更多内容并需要更多空间的列为代价。
但我发现了一种 CSS 小技巧式的解决方法,可以帮助简化操作。 我想在本篇文章中向大家展示它。
问题
首先我们需要了解浏览器如何处理布局。 我们在 CSS 中有 table-layout
属性来定义表格应该如何分配每个表格列的宽度。 它接受两个值之一
auto
(默认值)fixed
让我们从一个没有定义任何列宽度的表格开始。 换句话说,我们将让浏览器通过在 CSS 中对它应用 table-layout: auto
来决定每个列应该分配多少宽度。 正如您将注意到的,浏览器会尽其所能使用其拥有的算法将整个可用宽度划分为每一列。
如果我们将自动表格布局替换为 table-layout: fixed
,那么浏览器将仅将整个可用空间除以总列数,然后将该值作为每个列的宽度应用。
但是如果我们想控制列的宽度呢? 我们有 <colgroup>
元素来帮助我们! 它由我们可以用来指定每个列所需的确切宽度的单个 <col>
元素组成。 让我们看看它在 table-layout: auto
中是如何工作的
为了说明目的,我内联了样式。
浏览器不尊重内联宽度,因为它们加起来超过了表格的可用空间。 结果,表格从列中窃取空间,以便所有列都可见。 这是完全正常的默认行为。
<colgroup>
如何与 table-layout: fixed
一起使用。 让我们来发现一下
这看起来一点也不好。 我们需要内容丰富的列进行一些伸缩,同时为其他列保持固定宽度。 固定 table-layout
值尊重宽度——但如此强烈以至于它占用了最需要空间的列的空间……这对我们来说是不可接受的。
如果我们能设置一个 min-width
在列上而不是一个 width
,这就可以轻松解决。 这样,该列就会说:“我可以把我的宽度中的一部分给你们所有人,直到我们达到这个最小值。“ 然后表格将简单地超出其容器,并为用户提供水平滚动条来显示表格的其余部分。 但是不幸的是,min-width
在表格列上不会被 <col>
元素尊重。
解决方案
解决方案是伪造一个 min-width
,我们需要创造性地做这件事。
我们可以在 HTML 中将一个空 <col>
作为 <colgroup>
中的第二列,并在第一列上应用一个 colspan
属性,以便第一列占用两列的空间。
<table>
<colgroup>
<col class="col-200" />
<col />
<col class="col-input" />
<col class="col-date" />
<col class="col-edit" />
</colgroup>
<thead>
<tr>
<th colspan="2">Project name</th>
<th>Amount</th>
<th>Date</th>
<th>Edit</th>
</tr>
</thead>
<!-- etc. -->
</table>
请注意,我已经添加了类来代替前一个示例中的内联样式。 相同的想法仍然适用:我们正在对每一列应用宽度。
诀窍在于第一 <col>
和空第二 <col>
之间的关系。 如果我们对第一 <col>
应用一个宽度(它在上面的代码段中是 200px
),那么当固定表格布局划分可用空间以分配给列时,第二列将被占用。 但第一列的宽度(200px
)将被尊重并保留在适当的位置。
瞧! 我们在表格单元格上设置了一个伪 min-width
。 随着可用空间的变化,第一个单元格会伸缩,表格会像我们希望的那样溢出以进行水平滚动。
(我在第一列中添加了一些 粘性定位。)
可访问性
让我们不要完全忘记这里关于可访问性的事情。 我在 Windows 上使用 NVDA 和在 macOS 上使用 VoiceOver 运行了表格,发现所有五个列都被宣布,即使我们只使用了其中的四个。 当第一列处于焦点时,它会宣布,“第一列到第二列”。 虽然不是完美优雅,但也不会造成用户迷路。 我想我们可以向未使用的那一列添加一个 aria-hidden
属性,但我们也知道 ARIA 并不是糟糕 HTML 的替代品。
我承认,这感觉有点,嗯,有点 hacky。 但它确实有效! 如果你在评论区中有不同的方法……或者知道这个“hack”可能会给我们的用户带来哪些困惑,请告诉我。
空
col
感觉有点破坏了表格的语义。另一种可能的解决方案是使用
max
和calc
与vw
单位来确定第一列的大小——类似于如果表格具有最大宽度,则必须使用
clamp
来设置表格达到最大宽度后列的宽度。演示:https://codepen.io/chriskoelle/pen/NWBpOKJ
这种解决方案诚然可能会变得更加复杂,具体取决于围绕表格的页面布局。
有趣。 你是怎么决定 680px 的?
我一直使用 Angular 和 PrimeNG 表格这样做,只是我发现使用 % 比使用 px 更安全。 我通常会将一列保留为“auto”。
为什么不直接使用 display grid 与表格并设置 trs、thead、tfoot、tbody 为 display contents。 然后你可以使用 grid 的强大功能来按照你的喜好格式化表格。
这也是一种方法。 我知道 css display content 存在破坏语义的问题。 该问题仍然在此处开放:https://github.com/w3c/csswg-drafts/issues/3040
不知道它是否仍然是一个问题——最近没有测试过。