必须为每个<th>显式设置scope属性:scope="col"用于<thead>中管正下方所有<td>的列标题,如“姓名”;scope="row"用于<tbody>每行首个管右侧同<tr>内<td>的行标题,如“张三”;左上角空<th>不加scope;带rowspan/colspan的<th>必须显式声明,否则屏幕阅读器归属错乱。

不配 scope,屏幕阅读器就只能靠位置硬猜表头管谁——它不报错,但用户听到的是错的归属关系。
scope="col" 和 scope="row" 怎么选?只看“它管谁”
判断完全机械,和文字内容、视觉位置无关:
-
scope="col":该<th> 正下方所有 <code><td> 都归它管;几乎全部出现在 <code><thead> 里,比如“姓名”“销售额”“部门” <li> <code>scope="row":该<th> 右侧同 <code><tr> 内的所有 <code><td> 都归它管;只应出现在 <code><tbody> 每行第一个单元格,比如“张三”“李四” <li>左上角那个空 <code><th>(<code><th></th>)不要加scope,它既不属列也不属行,加了反而误导带 rowspan 或 colspan 的 th 必须显式设 scope
浏览器对合并单元格的语义推断极不可靠。哪怕只是
rowspan="2"的列标题,不加scope="col",屏幕阅读器可能把第二行数据全算作第一行表头的下属。- 只要
<th> 是列标题(哪怕 <code>rowspan="2"),一律用scope="col" - 如果
<th> 用 <code>colspan="3"统领一组列(如“Q1 业绩”),可考虑scope="colgroup",但必须确保业务逻辑上这三列确实构成一个语义组 - 没包
<colgroup></colgroup>却写scope="colgroup",旧版 JAWS 会直接忽略整组列 - 没包
<tbody> 却写 <code>scope="rowgroup",等于没写动态生成表格时 scope 容易批量写错
别写
if (i === 0) scope="row"就完事——得区分当前是循环列头还是行头。立即学习“前端免费学习笔记(深入)”;
- 遍历
<thead> 时,每个 <code><th> 应为 <code>scope="col" - 遍历
<tbody> 每行时,第一个单元格如果是 <code><th>,才设 <code>scope="row";其余必须是<td> 或明确标注 <code>scope="col"(极少见) - 用模板引擎(如 Handlebars、Vue)时,避免在列循环中误把
scope="row"插入到所有<th> 上 <li>验证方法:用 NVDA 或 VoiceOver 进入表格后听读,若某 <code><td> 只读出数值、没补读对应列名,说明上方 <code><th> 缺 <code>scope或值错误最难的不是写对某一行
scope,而是在每次插入<th> 时都条件反射地问一句:“它管的是列,还是行?”——这个习惯一旦建立,比任何检测工具都管用。复杂结构下,<code>scope往往只是起点,真正要靠id和headers把跨行、跳格、多对一的关系钉死。
- 遍历
- 只要



















