可访问性树与dom结构不一致的直接验证方式是:打开chrome devtools→elements面板→右键节点→选show accessibility properties,若role/name等字段为空或与dom中实际父子关系不符,即表明浏览器容错修复导致两者脱钩。

怎么确认可访问性树和DOM结构不一致
浏览器解析HTML时,若遇到非法嵌套(比如 <p></p>
<div></div>
最直接验证方式是打开 Chrome DevTools → Elements 面板 → 右键任意节点 → 选 Show accessibility properties。如果看到 role、name、description 等字段为空或与预期不符,说明可访问性树已退化;再对比左侧DOM树中该节点的实际父/子关系,就能定位是否被浏览器容错修复过。
- 检查
document.compatMode:返回"BackCompat"表示怪异模式,可访问性树基础已不可靠 - 用
getComputedAccessibleNode()(Chrome 120+)直接抓取节点的可访问性属性,比手动点面板更准 - 对
<nav></nav>、<main></main>、<section></section>这类语义标签,必须确保它们在可访问性树中显示为对应role,而不是 fallback 成generic
为什么 aria-hidden="true" 有时没生效
常见现象:给某个容器加了 aria-hidden="true",但屏幕阅读器依然读出里面的内容。根本原因不是属性写错了,而是该容器内部存在可聚焦元素(如 <button></button>、<a href></a>、带 tabindex="0" 的 <div>)。WAI-ARIA 规范明确要求:只要一个元素可聚焦,它就自动脱离 <code>aria-hidden 的屏蔽范围。
- 不要依赖
aria-hidden来“隐藏交互区域”,它只管语义可见性,不管焦点流 - 真正要隐藏且禁用交互,得组合使用:
aria-hidden="true"+inert(现代浏览器支持)或tabindex="-1"+ CSSvisibility: hidden - 特别注意 Vue/React 中动态插入的内容:JS 插入后未同步更新
aria-hidden状态,会导致可访问性树滞后
表单控件缺失 label 为何影响不止屏幕阅读器
没写 <label for="xxx"></label> 或没把输入框包进 <label></label>,表面看只是屏幕阅读器读不出提示文字,实际后果更隐蔽:
- 点击
<label></label>文本无法聚焦对应输入框 → 触屏用户操作半径缩小50% Chrome 的 autofill 下拉菜单可能完全不触发,因为缺少关联上下文
- Lighthouse 的
label-elements审计失败,间接拉低 SEO 权重(Google 明确将表单可访问性纳入页面质量信号) - 某些辅助技术(如 Dragon NaturallySpeaking)依赖 label 关联执行语音命令,缺失即失效
修复不是加个 <span></span> 就完事:必须用真实 <label></label> 元素,且 for 值与 input 的 id 严格匹配(大小写、连字符、空格全敏感)。
树形菜单里 role="treeitem" 不被识别的典型原因
即使写了 role="treeitem",屏幕阅读器仍当普通列表项读,大概率卡在三个硬性条件上:
-
<ul role="tree"></ul>缺失,或写成了<div role="tree"> —— ARIA 树必须基于 list 结构,否则可访问性树拒绝构建层级 <li>父级 <code><li>没套<ul></ul>或<ol></ol>,导致子节点无法被识别为 treeitem 的子集 - 没配
aria-expanded(折叠态)或aria-level(当前深度),可访问性树判定该节点无交互语义,降级为静态文本
验证方法:用 NVDA 或 VoiceOver 进入虚拟光标模式,按 Insert + F7 打开元素列表,看是否出现 “tree” 类型条目;没有,就说明树结构未被正确暴露。
aria-* 同步更新时,两者就彻底脱钩了。











