多级表头必须用thead内多行tr配合colspan和rowspan实现,不可嵌套th或div;每行tr的单元格列数总和须一致,最底层th统一用scope="col",确保语义正确与无障碍可访问。

多级表头必须用 colspan 和 rowspan 配合 thead 多行 tr
不能靠嵌套 th 或 div 实现,浏览器和读屏器只认表格 DOM 结构。核心是:用 thead 里多个 tr 表示层级,每个 th 通过 colspan(横向占几列)和 rowspan(纵向占几行)声明覆盖范围。
常见错误现象:th 视觉上对齐了,但 tbody 数据列错位;读屏器跳读、漏读、重复读某列。
- 第一行
tr中的th若跨多列(如分组标题),必须设colspan="N",同时该th的rowspan通常为1或2(取决于它是否需要延伸到下层) - 第二行
tr的每个th对应最终数据列,一律用scope="col",且不设colspan(除非它本身还要再分) - 顶层
th(最上一行)若只占一列但需跨两行对齐数据,就用rowspan="2",不用colspan
scope 属性怎么填才不翻车
95% 场景只需所有最终列头(即最底层 th)统一写 scope="col"。别乱用 scope="colgroup" —— 它不是“二级表头专用”,而是语义上声明“这个标题管下面一整组列”,但不会自动绑定任何实际结构,纯靠开发者手动保证逻辑一致。
容易踩的坑:scope 缺失、写成 scope="column"(非法值)、或在中间层 th 上强行写 scope="colgroup" 却没对应 colspan 逻辑。
立即学习“前端免费学习笔记(深入)”;
- 只要该
th直接对应 tbody 中某一列(哪怕它上面有父级分组),就用scope="col" - 如果某
th用colspan="3"覆盖三列,且这三列在业务上确属同一逻辑组(如“Q1 销售”含“线上”“线下”“代理”),可考虑scope="colgroup",但非必需 - 绝对不要给
rowspan > 1的顶层th(如员工姓名列)写scope="row"——它仍是列头,不是行头
怎么验证多级表头结构没崩
关键不是“看起来整齐”,而是每行 tr 在逻辑列数上必须一致。浏览器按 DOM 中 th/td 数量 + colspan/rowspan 声明推导列序,一旦某行少写一个 th 又没用 colspan 补足,后面全乱。
实操建议:
- 先算总列数:把第一行所有
th的colspan值加起来(没写默认为 1),记为 N - 检查每一行
tr:其内部th和td的colspan总和必须等于 N(rowspan不影响列数统计) - 用浏览器 DevTools 查看
table的 computed layout,或运行document.querySelector('table').rows[0].cells.length看是否与预期一致 - 用 NVDA / VoiceOver 实际听一遍:从左到右逐列移动,确认每列播报内容和数据能准确对应
复杂场景下 colgroup 有用吗
基本没用。知识库明确指出:colgroup + col 不是构建多级表头的必要手段,也**不参与语义绑定**。scope="colgroup" 是独立语义声明,跟有没有 colgroup 元素完全无关。
真实影响只在 CSS 控制列宽时有点用(比如 <col width="120">),但现代开发更倾向用 CSS Grid 或 JS 动态列宽控制。硬塞 colgroup 还可能干扰某些表格库的列映射逻辑。
- 不要为了“看起来规范”而加
colgroup,除非你真要用它设固定列宽或背景色 - 加了
colgroup后,务必确保col数量等于最终列数(即第一行colspan总和),否则列宽错位 - 无障碍检测工具(如 axe)不检查
colgroup,只校验th结构和scope
thead 里行数正确、colspan/rowspan 计算无误、scope 统一且合理,结构就稳了。样式可以后期补,结构错了,读屏器和自动化工具立刻失效。



















