语义化表格必须包含和,表头用并正确设置scope或id/headers,禁用css模拟表格,排序需用aria-sort和aria-live同步状态。

table 必须有 <thead> 和 <code><tbody><p>没有 <code><thead> 的 <code><table> 在语义上等于告诉屏幕阅读器“这是一堆没头没尾的单元格”,辅助技术无法识别哪行是标题、哪行是数据。即使视觉上只有一行表头,也必须用 <code><thead><tr><th>...</th></tr></thead> 包裹。
常见错误:
– 直接用 <tr>
<td>姓名</td>
<td>年龄</td>
</tr> 当表头
– 把所有行都塞进 <tbody>,漏掉 <code><thead>
<br>– 用 <code><div role="table"> 替代原生 <code><table>(放弃语义和键盘导航支持)
<p>正确结构骨架:</p>
<pre class="brush:php;toolbar:false;"></pre>
<table>
<thead><tr>
<th>姓名</th>
<th>邮箱</th>
<th>入职时间</th>
</tr></thead>
<tbody><tr>
<td>张三</td>
<td>zhang@example.com</td>
<td>2022-03-15</td>
</tr></tbody>
</table>
<h3><code><th> 要带 <code>scope 属性或明确的 id/headers 关联
单层表头(一行列名)用 scope="col" 是最简方案;多级表头(比如“Q1”下分“收入”“支出”)必须用 id + headers 显式绑定,否则屏幕阅读器读不出归属关系。
容易忽略的点:
– <th scope="row"> 用于首列标识行(如“张三”那列),不是所有 <code><th> 都该设 <code>scope="col"
– scope 值只能是 row、col、rowgroup、colgroup,写成 "column" 或空字符串无效
– 如果用了 <colgroup></colgroup>,<col> 标签本身不参与语义关联,不能替代 scope
数据表格禁用 display: grid 或 flex 模拟
用 CSS 把 <div> 排成表格样式,再加 <code>role="table",看起来像表格,但实际:键盘 Tab 无法按行列跳转、<th> 的语义丢失、打印时布局崩坏、<code>Ctrl+F 搜索失效。
什么情况可以破例?
– 纯装饰性栅格(比如图标网格、卡片列表),且内容无行列逻辑关系
– 动态宽高自适应布局,且明确不需要排序、导出、辅助访问
– 但此时应改用 <ul></ul> 或 <section></section>,而不是硬套 table 语义
真实数据表格,哪怕样式再复杂,也要坚持原生 <table> 结构,用 CSS <code>table-layout、border-collapse 或现代属性(如 sticky 表头)来控制外观。
可排序/可筛选表格要暴露状态给辅助技术
点击表头排序后,仅靠颜色或箭头图标是不够的。必须用 ARIA 属性声明当前状态:
-
<th aria-sort="ascending">姓名</th>(升序) -
<th aria-sort="descending">姓名</th>(降序) -
<th aria-sort="none">姓名</th>(未排序,默认值,建议显式写出)
注意:
– 不要用 aria-label 覆盖原有文本(如 aria-label="姓名,点击升序"),会吞掉原 <th> 内容<br>– 排序状态变更后,需用 <code>aria-live 区域播报结果(例如“已按邮箱升序排列,共 24 条”),否则视障用户不知道操作是否生效
– 如果表格支持多列排序(如先按部门、再按姓名),aria-sort 只能标记主排序列,次序需在 aria-describedby 中补充说明
语义化表格最难的部分不在结构,而在交互状态的可感知性——视觉反馈和 ARIA 状态必须同步更新,缺一不可。










