HTML 的 `<thead>` `<tbody>` `<tfoot>` 正确使用?可能没提,但表格可访问性有部分。
thead、tbody、tfoot 用于表格行分组并提供结构语义,HTML5 中 tfoot 应写在 tbody 之后,省略 tbody 会被浏览器自动补全并影响 CSS 选择器;可访问性还需配合 caption、th 的 scope,复杂
结论:<thead>、<tbody>、<tfoot> 不改变表格的默认外观,它们的作用是给浏览器、屏幕阅读器和打印排版提供结构信息;真正决定表格"能不能被读懂"的,是 caption、th 的 scope 和行分组这三者配合,少一个都会让可访问性打折。
thead、tbody、tfoot 到底解决什么问题?
结论:这三个标签是表格的「行分组」元素,把表格拆成表头区、数据区、汇总区,浏览器和辅助技术据此判断哪一行是表头、哪一行是数据。
<thead> 放列标题行,<tbody> 放数据行,<tfoot> 放合计、平均之类的汇总行。屏幕阅读器在读取某个单元格时,会沿着行分组的语义往上找对应的 th,用户按快捷键跳转表格时也能按"表头区/数据区"整块跳,而不是一行行爬。
它们各有隐式 ARIA 角色:thead/tbody/tfoot 是 rowgroup,tr 是 row,th 是 columnheader 或 rowheader,td 是 cell。也就是说,你不用手写 role="rowgroup",写对标签本身就够了——这也是为什么要用原生标签而不是一堆 div 拼表格。
tfoot 应该写在 tbody 前面还是后面?
结论:按现行的 HTML5 规范,tfoot 要写在 tbody 之后;HTML4 时代允许把它放在 thead 后面,这个老写法现代浏览器仍能渲染到底部,但源码顺序已经不合规,新代码统一写到 tbody 之后。
顺序记法很简单:caption → colgroup → thead → tbody(可以多个)→ tfoot。caption 必须是 table 的第一个子元素,放错位置浏览器会直接把它踢出表格。
浏览器不会因为你把 tfoot 写在前面就把它显示在中间,视觉上它永远贴底,所以"看起来没问题"不代表写对了——问题会出现在自动化测试、静态检查和别人读你的源码时。
不写 tbody 会怎样?
结论:不写 tbody 浏览器会自动补一个,DOM 里你会看到一个凭空出现的 <tbody>,结果 table > tr 这类 CSS 选择器直接失效。
只要你在 <table> 里直接写 <tr>,HTML 解析器就会插入隐式 tbody。很多人调样式时纳闷"为什么 table > tr 不生效",原因就在这里。要么显式写出 tbody,要么选择器改成 table tr 或 tbody tr。
多个 tbody 是被允许的,而且很有用:你可以把「第一季度」「第二季度」分成两个 tbody,各带一个类名做折叠、隔行变色或批量展开,比给每行加类名干净得多。
表格可访问性要补哪些属性?
结论:光有行分组还不够,必须给表头 th 加 scope,给整张表加 caption,这两步是投入产出比最高的。
scope的取值有四个:col(列头)、row(行头)、colgroup、rowgroup。普通二维表用col和row就够。caption写在<table>内的第一行,描述表格内容,屏幕阅读器进入表格时会先读它。想视觉隐藏又保留语义,用 CSS 裁剪而不是display: none。- 复杂表(一个单元格对应多个表头,比如合并单元格的课程表)用
id+headers手动建立关联:<td headers="name math">。这类表结构越复杂,scope越力不从心。 - 表头文本很长时,用
abbr属性给个短名,例如<th scope="col" abbr="GMV">商品交易总额</th>,读屏会念短名。
thead 在打印时有什么用?
结论:thead 里的行在打印分页时会在每一页顶部重复,这是 thead 唯一一个纯视觉上的实际收益。
Chrome、Firefox、Safari 都支持打印时重复 thead,长报表导出 PDF 时非常实用。tfoot 的重复行为各浏览器不一致,别把它当"每页页脚"来用,要页脚就用打印样式另做。
收尾
一句话记住:结构上 caption → colgroup → thead → tbody → tfoot,语义上 th 配 scope,样式上别依赖 table > tr。行分组不写也能跑,但写了之后,你的表格对屏幕阅读器、打印排版和三个月后的自己都更友好。
转载请注明出处,版权归原作者所有。