表格样式指南

2025-05-25

表格样式指南

我最近注意到一个小悖论:很多年前——在 CSS 网格出现之前——我们用<table>s 来模拟网格布局。现在有了网格布局,我们却用它们来模拟表格!这错了。表格是用来显示表格数据的;而用一堆<div>s 来呈现表格数据是没有意义的。

造成这种弊端的原因可能是表格的样式设置比较棘手,而且大多数 CSS 框架都border-collapse: collapse默认使用这种样式。正如我们将在本教程中看到的那样,折叠边框对于表格样式设置并不总是有用的。

让我们研究一下的元素<table>,然后了解如何构造和设置它们的样式。

元素

除了元素本身之外<table>,您只需要这 3 个标签即可制作基本表格:

标签 描述
td 表格数据单元格
th 表头单元格
tr 表格行

例子:

<table>
  <tr><th>Header</th></tr>
  <tr><td>Content</td></tr>
</table>
Enter fullscreen mode Exit fullscreen mode

但是,为了更好地构造表,我们可以将行封装在:

标签 描述
thead 表头
tbody 表体
tfoot 表页脚

最后,我们可以<caption>向表中添加一个,并<col>在一个内的标签中定义列<colgroup>

例子:

<table>
  <caption>Super Heroes</caption>
  <colgroup><col><col><col><col></colgroup>
  <thead>
    <tr><th>First Name</th><th>Last Name</th><th>Known As</th><th>Place</th></tr>
  </thead>
  <tbody>
    <tr><td>Bruce</td><td>Wayne</td><td>Batman</td><td>Gotham City</td></tr>
    <tr><td>Clark</td><td>Kent</td><td>Superman</td><td>Metropolis</td></tr>
    <tr><td>Tony</td><td>Stark</td><td>Iron Man</td><td>Malibu</td></tr>
    <tr><td>Peter</td><td>Parker</td><td>Spider-Man</td><td>New York City</td></tr>
    <tr><td>Matt</td><td>Murdock</td><td>Daredevil</td><td>New York City</td></tr>
  </tbody>
</table>
Enter fullscreen mode Exit fullscreen mode

如果没有任何样式,您的浏览器将会呈现如下内容:

基本表格浏览器样式

默认的用户代理样式是:

table {
  border-collapse: separate;
  text-indent: initial;
  border-spacing: 2px;
}
Enter fullscreen mode Exit fullscreen mode

现在,如果我们添加一个超级简单的规则:

:is(td,th) {
  border-style: solid;
}
Enter fullscreen mode Exit fullscreen mode

我们得到:

带实线边框的基本表格

注意看分开的边框。看起来不太好看……

因此,为了了解折叠边框(以及更好的字体!)的流行度,我们只需添加:

table {
  border-collapse: collapse;
  font-family: system-ui;
}
Enter fullscreen mode Exit fullscreen mode

...我们得到:

border-collapse 设置为折叠

如果我们随后将 添加padding: .5ch 1ch到我们的:is(td,th)-selector 并margin-block: 1rlh添加到<caption>,我们得到:

基本表格样式

回顾一下,获得上述样式,我们需要做的就是:

table {
  border-collapse: collapse;
  font-family: system-ui;
  & caption { margin-block: 1rlh; }
  &:is(td, th) {
    border-style: solid;
    padding: .5ch 1ch;
  }
}
Enter fullscreen mode Exit fullscreen mode

要将其放置在表格<caption> 下方,请使用:

table {
  caption-side: bottom;
}
Enter fullscreen mode Exit fullscreen mode

斑马条纹

要为列添加奇数/偶数斑马条纹,我们可以简单地设置<col>标签的样式:

col:nth-of-type(even) { background: #F2F2F2; }
Enter fullscreen mode Exit fullscreen mode

斑马上校

对于行来说,情况类似:

tr:nth-of-type(odd) { background: #F2F2F2; }
Enter fullscreen mode Exit fullscreen mode

斑马线


圆角

圆角有点棘手。你不能直接添加border-radius到 a <table>,所以我们必须定位到第一行最后一行的第一个最后一个单元格:

th {
  &:first-of-type { border-start-start-radius: .5em }
  &:last-of-type { border-start-end-radius: .5em }
}
tr {
  &:last-of-type {
    & td {
      &:first-of-type { border-end-start-radius: .5em }
      &:last-of-type { border-end-end-radius: .5em }
    }
  }
}
Enter fullscreen mode Exit fullscreen mode

……但什么也没发生!这是因为:

如果您的表格有折叠边框,则您无法添加border-radius

所以我们必须使用单独的边框,并模仿折叠的边框:

table {
  border-spacing: 0;
}
:is(td, th) {
  border-block-width: 1px 0;
  border-inline-width: 1px 0;
  &:last-of-type { border-inline-end-width: 1px }
}
Enter fullscreen mode Exit fullscreen mode

现在我们有了圆角:

圆角


拆分列

让我们保留单独的列,并使用border-spacing-property 在列之间添加间隙:

table {
  border-spacing: 2ch 0;
  & :is(td, th) {
    border-inline-width: 1px;
  }
}
Enter fullscreen mode Exit fullscreen mode

拆分列

我们甚至可以添加border-radius

边界半径

这仍然只是一个<table>,但如果用作“比较表”,则可读性会更高。


拆分行

对于拆分行,我们只需要更新属性的第二部分(y 轴)border-spacing

table {
  border-spacing: 0 2ch;
  & :is(td, th) {
    border-block-width: 1px;
  }
}
Enter fullscreen mode Exit fullscreen mode

拆分行


悬停和聚焦

对于大型表格,准确了解当前位置至关重要。为此,我们需要:hover,并且(如果您使用的是键盘导航表格)还:focus-visble需要 -styles。

在此示例中,悬停样式应用于<col><tr><td>

表格悬停示例

悬停行和单元格很简单:

td:hover {
  background: #666666;
}

tr:hover {
  background: #E6E6E6;
}
Enter fullscreen mode Exit fullscreen mode

悬停<col>有点复杂。

您可以添加一条规则:

col:hover {
  background: #E6E6E6;
}
Enter fullscreen mode Exit fullscreen mode

……但它不起作用。奇怪的是,如果你在 Dev Tools 中选择一个 col 元素并启用:hover它,它就能正常工作——但在现实生活中却不行。

相反,我们需要使用 来捕获单元格的悬停:has然后设置元素的样式<col>

table {
  &:has(:is(td,th):nth-child(1):hover col:nth-child(1) {
background: #E6E6E6;
}
Enter fullscreen mode Exit fullscreen mode

那么,到底发生了什么?

让我们分解一下:

如果我们的表格中一个<td> 或 ,<th>nth-child(1)并且它当前处于 悬停状态<col>使用相同的 -选择器选择nth-child,并将其设置为background

唷!...需要对每一列重复此代码:nth-child(2)nth-child(3)等等。


大纲

悬停时显示轮廓也很简单,单元格和行也一样。你需要从偏移量中减去宽度:

:is(td, th, tr):hover {
  outline: 2px solid #666;
  outline-offset: -2px;
}
Enter fullscreen mode Exit fullscreen mode

表格悬停:轮廓

列轮廓

勾勒出一列非常棘手,但看起来不错:

表格悬停:大纲列

如果单元格中有border-width1px则可以将 设置<col>悬停时 ,但整个表格都会移动。border-width2px

Álvaro Montoro 建议使用背景渐变来<col>模拟边框,如果表格单元格是透明的,这种方法就可以很好地工作。

为了使其能够与border-radius单元格可能具有的背景一起工作并保持其功能,我最终为每个单元格使用了一个伪元素:

:is(td,th) {
  position: relative;
  &::after {
    border-inline: 2px solid transparent;
    border-radius: inherit;
    content: '';
    inset: -2px 0 0 0;
    position: absolute;
  }
}
tr:first-of-type th::after {
  border-block-start: 2px solid transparent;
}
tr:last-of-type td::after {
  border-block-end: 2px solid transparent;
}
Enter fullscreen mode Exit fullscreen mode

...然后,类似于我们对 col-hover 所做的操作,在悬停时定位具有相同“col-index”的所有单元格:

:has(:is(td,th):nth-child(1):hover :is(td,th):nth-child(1) {
  border-color: #666;
}
Enter fullscreen mode Exit fullscreen mode

对所有列重复此操作。


对齐文本

在旧规范中,你可以align<col>元素添加属性。但现在这行不通了。

例如:您想让第二列的文本居中,第四列的文本右对齐:

表格:对齐文本

我们不需要为每个单元格添加一个类,而是可以为表格本身的每一列添加一个数据属性:

<table data-c2="center" data-c4="end">
Enter fullscreen mode Exit fullscreen mode

然后,在 CSS 中:

[data-c2~="center"] tr > *:nth-of-type(2) {
  text-align: center;
}
[data-c4~="end"] tr > *:nth-of-type(4) {
  text-align: end;
}
Enter fullscreen mode Exit fullscreen mode

对所有列重复此操作。


结论

这就是表格样式指南的全部内容。

我没有介绍colspan。如果你想深入了解这些内容,我建议阅读rowspanMDN表格页面scopespan

演示

我制作了一个 CodePen,其中包含一些演示:


更新

RioBrewster 在评论中写道:

您不需要:
<colgroup><col><col><col><col></colgroup>

您确实需要:<th scope="col">针对每个列标题。

让我用一个例子来回答这个问题。假设你想突出显示最后一列。使用<col>,你只需添加一个类:

<col class="highlight">
Enter fullscreen mode Exit fullscreen mode

在 CSS 中:

.highlight { background-color: HighLight; }
Enter fullscreen mode Exit fullscreen mode

返回:

强调

另一方面,如果您使用:

<th scope="col" class="highlight">...</th>
Enter fullscreen mode Exit fullscreen mode

您将获得:

突出显示范围

这显然行不通。我们必须补充一些内容。

请参阅MDN 的示例。它们<td scope="row">在每行的所有第一个单元格中添加了“突出显示该列”的功能。

这样,或者使用一堆nth--selectors 来突出显示一列,比简单地使用 -tag 要费力得多<col>

因此,在我看来,这不是“要么要么”,而是“要么并且”。

文章来源:https://dev.to/madsstoumann/a-guide-to-styling-tables-28d2
PREV
构建最小的 AutoSuggest
NEXT
加入我们的 JavaScript 读书俱乐部