表格可访问性
基于 HTML Living Standard · 核于 2026-06
速查
<caption>是表的可访问名称:一句话讲清主题,读屏用户据此决定细读还是跳过- 表头一律用
<th>并写scope(col/row)——读屏滚到任意格都能播报它对应的行/列表头 - 读屏有专门的「表格导航模式」:按行列方向移动焦点,每进一格自动念出关联的表头
- 复杂表(多级表头 / 大量合并)必须用
headers/id显式绑定,scope推断会失准 <th>的abbr给冗长表头一个简短播报名;表若「在说明一个观点」,再配简短摘要降低认知负担- 长摘要用
aria-describedby关联,或把表放进<figure>+<figcaption> - 改了 CSS
display就要补role:role="table"/rowgroup/row/columnheader/rowheader/cell,否则无障碍树被打散 - 交互表(可选中/二维键盘导航/可拖拽)该用
role="grid";行可展开折叠用role="treegrid" - 第一性原则:表越简单越无障碍——少合并、少嵌套,胜过事后堆一堆 ARIA 补救
读屏用户是怎么「看」表的
视觉用户一眼就能把握表的行列结构,读屏用户却是线性听的——所以辅助技术专门为表格提供了「表格导航模式」:用户可以按上下左右在单元格间移动焦点,每进入一格,读屏会自动播报这格对应的行表头与列表头,再念格子内容。
这套机制能不能用,全看 HTML 写得对不对。它依赖三样东西:一个说明主题的 <caption>、用 <th> 标出的表头、以及把表头和数据格绑起来的 scope(或复杂表的 headers/id)。这三样齐了,读屏用户才能像看见网格的人一样在表里穿行;缺了,表对他们就是一串失去坐标的散数据。
第一支柱:<caption> 给表一个名字
<table>
<caption>2021 年俱乐部成员状态</caption>
…
</table><caption> 是表的可访问名称。它对低视力用户和读屏用户尤其重要:先用一句话讲清「这是什么表」,他们就能快速判断这张表与自己是否相关,从而决定细读还是跳过——而不必让屏幕阅读器把一格格内容念完才搞懂主题。
除了 <caption>,也可以用 aria-label 或 aria-labelledby 给 <table> 起名,但 <caption> 是默认且对所有人可见的语义元素,应优先使用。
第二支柱:<th> + scope 建立行列关联
把表头写成 <th> 并标注 scope,是表格无障碍的核心动作:
<tr>
<th scope="col">姓名</th>
<th scope="col">毕业年份</th>
</tr>
<tr>
<th scope="row">娄敏秋</th>
<td>1956</td>
</tr>这样「1956」这格就拥有两个表头——「毕业年份」(列)与「娄敏秋」(行)——读屏会告诉用户「这是娄敏秋的毕业年份」。即便表很长、表头早滚出屏幕,这层关联依然牢固。scope 取 col / row 覆盖绝大多数规整表;rowgroup / colgroup 用于「一个表头统领整段行/整组列」(详见 单元格与表头关联)。
第三支柱:复杂表用 headers/id
规范明确指出:结构复杂的表——表头或单元格被合并、或有两级以上行/列表头——需要显式标明关联的表头格。这种表 scope 的自动推断会失准,必须给每个 <th> 编 id,再在数据格上用 headers 列出它隶属的所有表头 id:
<td headers="class-a final">92</td>读屏会据此播报「一班 / 期末 / 92」。这是无障碍领域对「拆不开的复杂表」的终极手段(完整示例见 单元格与表头关联)。
降低认知负担:摘要、abbr 与 <figure>
不是所有用户都有相同的认知能力。规范提醒:当一张表**「在说明某个观点」或需要解读**时,应额外给一段简短摘要,帮读者快速抓住要点:
- 长摘要:用
aria-describedby把表关联到页面上一段描述文字;或把表放进<figure>,用<figcaption>写说明。 - 冗长表头:用
<th abbr="简称">给读屏一个简短播报名,避免每念一格数据都重复一长串表头全称。
<figure>
<figcaption>各季度营收同比增长(数据来源:财报)。Q3 受促销拉动明显。</figcaption>
<table>…</table>
</figure>改了 display,务必补回 role
这是响应式表格最隐蔽的陷阱。如果你用 CSS 改了表格元素的 display(例如把 <table> 改成 display: block、把行改成 display: flex 来做手机端堆叠布局),表格的隐式 ARIA 语义会被破坏——浏览器不再把它当成 table / row / cell,无障碍树被打散,前面三支柱全部失效。
web.dev 给出的对策是:一旦为表格元素改了 display,就显式补回对应的 role,即便看起来冗余:
| 元素 | 需补的 role |
|---|---|
<table> | role="table" |
<thead> / <tbody> / <tfoot> | role="rowgroup" |
<tr> | role="row" |
<th>(列) | role="columnheader" |
<th>(行) | role="rowheader" |
<td> | role="cell" |
「看起来多余」不等于可以省
display 属性会实打实地影响无障碍树。改了 display 又不补 role,视觉上表格照常,读屏却已读不出行列关系——这是典型的「看不见的回归」。响应式方案务必连带验证无障碍。
交互表:role="grid" 与 role="treegrid"
普通展示型数据表用原生 <table> 即可。但当表格带交互时,要换更强的角色:
role="grid":表格维护选中状态、支持二维(行列双向)键盘导航、或允许重排单元格时使用;role="treegrid":在 grid 基础上,行还能展开 / 折叠(树形表格)时使用。
这两种角色伴随一整套键盘交互契约(方向键移动、Enter/Space 操作等),用它们就得把交互补全,否则反而更糟。普通只读表不要乱加 grid。
第一性原则:简单 > 补救
贯穿本页的一条主线:表越简单,越无障碍。少合并、少嵌套、少两级表头的表,哪怕不加 scope / headers 也更容易被理解,维护成本也更低。ARIA(role、headers/id、aria-describedby)是「原生结构表达不了时」的补救,不是用来给一张过度复杂的表打补丁。先把表设计简单,再谈无障碍增强。
小结
表格无障碍立在三根支柱上——<caption> 给名字、<th> + scope 建关联、复杂表用 headers/id 显式绑定;改 display 必补 role,交互表才用 grid / treegrid,而一切的前提是把表设计得足够简单。下一页把视角拉到最根本的反模式:为什么绝不能拿表格来排版,以及响应式表格该怎么做:数据表 vs 布局表。