headers不是“建立关联”,而是声明归属——它只告诉屏幕阅读器“这个<td>属于哪些<th id>”,不触发JS行为、不改变DOM、不影响样式;必须指向同表内已定义的id,大小写严格匹配,多级表头需逐级绑定,动态渲染时须确保<th id>先于<td headers>挂载。

直接说结论:headers 不是“建立关联”,而是**声明归属**——它只告诉屏幕阅读器“这个 <td> 属于哪些 <th id>”,不触发任何 JS 行为、不改变 DOM、不影响样式。想靠它实现联动或筛选,必须配 JS。
headers 必须指向同表内已定义的 id
这是最常断连的点:写了 headers="year q1",但 <th id="year"> 根本没写,或者写在了另一个 <table> 里,甚至用了 class="year" 代替 id。
-
<th>必须显式带id,且值全小写、无空格、无特殊字符(id="Q1-2024"合法,id="Q1 2024"非法) -
<td headers="year q1">中的每个 ID 都得在当前<table>内真实存在,大小写严格匹配 - 动态插入表头时,漏掉
el.id = "q1"是高频失误;服务端渲染后客户端又改 ID,也会导致首次无障碍树失效
多级表头怎么写 headers 值
不是把所有父级 id 全塞进去,而是按语义层级逐级绑定。比如“年份 → 季度 → 城市”,底层 <td> 只需直接关联最近一级的 <th id="beijing">,而 <th id="q1"> 自己再用 headers="year" 关联上层。
- 正确:
<th id="year">年份</th>,<th id="q1" headers="year">Q1</th>,<td headers="q1 beijing">120</td> - 错误:
<td headers="year q1 beijing">—— 会导致读屏器重复播报“年份 Q1 120, Q1 Q1 120” -
headers值必须用空格分隔,headers="year,q1"或headers=""year" "q1""全无效
为什么写了 headers 还被 Lighthouse 报错
报 “<td> missing header” 几乎从不是语法问题,而是 DOM 状态不一致:
立即学习“前端免费学习笔记(深入)”;
- ID 拼错一个字母(
id="sales"vsheaders="sale") -
<th id="hidden-header">被display: none隐藏,但仍在 DOM 中——读屏器会读出它,造成冗余;应移除 ID 或改用aria-label - 表格由 React/Vue 渲染,
<th id>在<td headers>挂载之后才生成,首次无障碍树无关联 - 混用了
scope和headers,调试时误以为 scope 还起作用(实际headers优先级永远更高,scope被完全忽略)
真正容易被忽略的是:headers 的生效前提是“DOM 可达”——ID 必须在 <td> 渲染完成前就存在于同一文档流中,哪怕它视觉上不可见,只要节点还在,语义就成立。



















