表格样式指南
我最近注意到一个小悖论:很多年前——在 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>
但是,为了更好地构造表,我们可以将行封装在:
标签 | 描述 |
---|---|
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>
如果没有任何样式,您的浏览器将会呈现如下内容:
默认的用户代理样式是:
table {
border-collapse: separate;
text-indent: initial;
border-spacing: 2px;
}
现在,如果我们添加一个超级简单的规则:
:is(td,th) {
border-style: solid;
}
我们得到:
注意看分开的边框。看起来不太好看……
因此,为了了解折叠边框(以及更好的字体!)的流行度,我们只需添加:
table {
border-collapse: collapse;
font-family: system-ui;
}
...我们得到:
如果我们随后将 添加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;
}
}
要将其放置在表格<caption>
下方,请使用:
table {
caption-side: bottom;
}
斑马条纹
要为列添加奇数/偶数斑马条纹,我们可以简单地设置<col>
标签的样式:
col:nth-of-type(even) { background: #F2F2F2; }
对于行来说,情况类似:
tr:nth-of-type(odd) { background: #F2F2F2; }
圆角
圆角有点棘手。你不能直接添加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 }
}
}
}
……但什么也没发生!这是因为:
如果您的表格有折叠边框,则您无法添加
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 }
}
现在我们有了圆角:
拆分列
让我们保留单独的列,并使用border-spacing
-property 在列之间添加间隙:
table {
border-spacing: 2ch 0;
& :is(td, th) {
border-inline-width: 1px;
}
}
我们甚至可以添加border-radius
:
这仍然只是一个<table>
,但如果用作“比较表”,则可读性会更高。
拆分行
对于拆分行,我们只需要更新属性的第二部分(y 轴)border-spacing
:
table {
border-spacing: 0 2ch;
& :is(td, th) {
border-block-width: 1px;
}
}
悬停和聚焦
对于大型表格,准确了解当前位置至关重要。为此,我们需要:hover
,并且(如果您使用的是键盘导航表格)还:focus-visble
需要 -styles。
在此示例中,悬停样式应用于<col>
和<tr>
:<td>
悬停行和单元格很简单:
td:hover {
background: #666666;
}
tr:hover {
background: #E6E6E6;
}
悬停<col>
有点复杂。
您可以添加一条规则:
col:hover {
background: #E6E6E6;
}
……但它不起作用。奇怪的是,如果你在 Dev Tools 中选择一个 col 元素并启用:hover
它,它就能正常工作——但在现实生活中却不行。
相反,我们需要使用 来捕获单元格的悬停:has
,然后设置元素的样式<col>
:
table {
&:has(:is(td,th):nth-child(1):hover col:nth-child(1) {
background: #E6E6E6;
}
那么,到底发生了什么?
让我们分解一下:
如果我们的表格中有一个<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;
}
列轮廓
勾勒出一列非常棘手,但看起来不错:
如果单元格中有border-width
,1px
则可以将 设置为<col>
悬停时 ,但整个表格都会移动。border-width
2px
Á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;
}
...然后,类似于我们对 col-hover 所做的操作,在悬停时定位具有相同“col-index”的所有单元格:
:has(:is(td,th):nth-child(1):hover :is(td,th):nth-child(1) {
border-color: #666;
}
对所有列重复此操作。
对齐文本
在旧规范中,你可以align
为<col>
元素添加属性。但现在这行不通了。
例如:您想让第二列的文本居中,第四列的文本右对齐:
我们不需要为每个单元格添加一个类,而是可以为表格本身的每一列添加一个数据属性:
<table data-c2="center" data-c4="end">
然后,在 CSS 中:
[data-c2~="center"] tr > *:nth-of-type(2) {
text-align: center;
}
[data-c4~="end"] tr > *:nth-of-type(4) {
text-align: end;
}
对所有列重复此操作。
结论
这就是表格样式指南的全部内容。
我没有介绍colspan
、和。如果你想深入了解这些内容,我建议阅读rowspan
MDN表格页面。scope
span
演示
我制作了一个 CodePen,其中包含一些演示:
更新
RioBrewster 在评论中写道:
您不需要:
<colgroup><col><col><col><col></colgroup>
您确实需要:
<th scope="col">
针对每个列标题。
让我用一个例子来回答这个问题。假设你想突出显示最后一列。使用<col>
,你只需添加一个类:
<col class="highlight">
在 CSS 中:
.highlight { background-color: HighLight; }
返回:
另一方面,如果您使用:
<th scope="col" class="highlight">...</th>
您将获得:
这显然行不通。我们必须补充一些内容。
请参阅MDN 的示例。它们<td scope="row">
在每行的所有第一个单元格中添加了“突出显示该列”的功能。
这样,或者使用一堆nth-
-selectors 来突出显示一列,比简单地使用 -tag 要费力得多<col>
。
因此,在我看来,这不是“要么要么”,而是“要么并且”。
文章来源:https://dev.to/madsstoumann/a-guide-to-styling-tables-28d2