伪造表格列的最小宽度

Avatar of Anders Pedersen
Anders Pedersen

DigitalOcean 为您的每个旅程阶段提供云产品。 立即开始使用 价值 200 美元的免费积分!

良好的旧 <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”可能会给我们的用户带来哪些困惑,请告诉我。