headers属性仅在th有匹配id时才生效,必须严格字符串匹配(大小写、空格敏感),多级表头需空格分隔多个id且不可省略,headers优先级高于scope并完全覆盖后者,动态渲染须确保th的id先于td的headers挂载到DOM。

headers 属性不是“写了就关联”,它只在 th 有匹配的 id 时才生效,且必须严格字符串匹配——大小写、空格、顺序全敏感。没效果?八成是 id 没设、设错,或 DOM 时机不对。
为什么写了 headers="name" 却没读屏效果
根本原因:浏览器和屏幕阅读器不查 class、不看文本、不推断位置,只去 DOM 里按字符串找 id。常见失效场景:
-
<th>姓名</th>没加id,光写<td headers="name">→ 完全无效 -
<th id="Name">姓名</th>和<td headers="name">→ 大小写不一致,匹配失败 -
<th id="name dept">部门</th>→id含空格非法,浏览器忽略该id - JS 动态插入
<th id="name">,但<td headers="name">已提前渲染 → 首次无障碍树无关联
多级表头下 headers 怎么写才对
一个 td 要同时归属「年份 + 季度 + 地区」,headers 值必须是空格分隔的完整 id 列表,不能省略、不能用逗号、不能加引号:
- ✅ 正确:
<td headers="year q1 beijing">120</td> - ❌ 错误:
headers="year,q1,beijing"(逗号分隔 → 当作单个 ID 查找) - ❌ 错误:
headers=""year" "q1" "beijing"(引号成为 ID 字符一部分) - ❌ 错误:
headers="year q1"(漏掉beijing→ 屏幕阅读器只读出前两个维度)
顺序不影响关联结果,但影响读屏播报次序 —— headers="q1 year" 和 headers="year q1" 都能关联成功,但读出来是“Q1 XXX,年份 XXX”还是“年份 XXX,Q1 XXX”。
立即学习“前端免费学习笔记(深入)”;
headers 和 scope 能不能一起用
不能。WAI-ARIA 明确规定:headers 优先级高于 scope,只要 td 上有 headers,scope 就被完全忽略。这不是互补,而是替代。
- 混用只会增加冗余,调试时还容易误判问题来源
- 别为了“兼容老读屏器”硬加
scope—— NVDA、VoiceOver、JAWS 2022+ 全支持headers,且更准确 - 如果表格结构简单(单层行列头),用
scope更轻量;复杂嵌套或多维语义,必须用headers+id
动态渲染表格时怎么避免 headers 失效
React/Vue 项目里最常踩的坑:表头 th 是异步加载或条件渲染的,id 还没挂载,td 的 headers 就已存在。
- 确保
th的id在组件挂载时同步设置,比如 Vue 中用v-if渲染th时,td也得等同批 DOM 就绪后再渲染 - 避免用
display: none或aria-hidden="true"隐藏关键th—— 只要 DOM 中存在且有id,读屏器就会读它,可能造成重复播报 - 调试必看 Chrome DevTools 的 Accessibility 面板:选中
td,右侧 “Related headers” 列出的才是真实生效的id,不是靠肉眼数位置
真正难的不是写对语法,而是让每个被引用的 th 的 id 在正确时间、以正确形式存在于 DOM 中 —— 动态场景下,这比静态 HTML 多一层时序控制。



















