Chrome DevTools Accessibility Inspector是唯一可信入口,右键元素选“Inspect Accessibility Properties”或按Ctrl+Shift+P(Win)/Cmd+Shift+P(Mac)输入“Accessibility”打开,重点检查Computed Role、Name、States三列是否真实反映屏幕阅读器读取内容。

Chrome DevTools Accessibility Inspector 是唯一可信入口
别信 Lighthouse 报告或 axe 扫描结果——它们只做静态分析,无法反映真实可访问性树状态。真正能告诉你“屏幕阅读器到底看到什么”的,只有 Chrome 的 Accessibility Inspector。打开方式:右键任意元素 → Inspect Accessibility Properties,或按 Ctrl+Shift+P(Win)/Cmd+Shift+P(Mac)输入 “Accessibility” 调出面板。
重点盯三列:Computed Role(它被识别成什么)、Name(读屏器实际朗读的名称)、States(如 expanded、invalid 是否同步)。比如一个 <nav></nav> 的 Computed Role 显示为 generic,说明它已被 display: none 或 JS 移除,根本不在可访问性树里。
aria-label 和 aria-labelledby 不生效?先查 Name 列是否为空
很多项目写了 aria-label="提交" 却没被读出来,不是属性写错了,而是 Name 列显示为空或 ""。常见原因:
-
aria-label值是空字符串(aria-label="")或纯空白(aria-label=" "),这类一律无效,应清理 -
aria-labelledby指向的 ID 不存在、拼写错误、或目标元素本身不可访问(比如被display: none包裹) - 同时写了
aria-label和aria-labelledby,后者被静音,且部分工具会报错 - 目标文本节点含不可见字符(如 BOM、换行符),导致 ID 匹配失败
验证方法:在 Accessibility Inspector 中点开该元素,看 Name 列是否显示你预期的字符串。不显示,就说明链路断了。
立即学习“前端免费学习笔记(深入)”;
aria-live 静默?检查 DOM 插入方式而非属性值
aria-live="polite" 不播报,90% 不是属性写错了,而是内容更新方式破坏了监听上下文:
- 用
innerHTML = newHtml替换整个容器 → 节点重建,旧引用丢失,aria-live失效 - 用
textContent = ""清空后,再appendChild()或insertAdjacentElement("beforeend", newItem)→ 正确,读屏器能感知新增节点 - 容器本身被
aria-hidden="true"父级包裹 → 子元素无论怎么设aria-live都无效(继承强制) - 在 VoiceOver 浏览模式下,
aria-live="polite"默认不触发,需用户已聚焦该区域才响应
简单验证:手动在控制台执行 el.appendChild(document.createTextNode("test")),看是否立刻被读出。不读,说明容器或父级有屏蔽逻辑。
第三方组件生成的 aria- 属性不能随便删
React Aria、Headless UI、MUI 这些库生成的 aria- 属性,往往绑定运行时状态(比如 aria-expanded 由 React state 控制)。盲目删除会导致:
- 键盘导航失效(Tab 进不去下拉菜单)
- 读屏器状态不同步(按钮显示“展开”,实际已收起)
- 焦点管理崩溃(模态框打开后背景仍可聚焦)
判断是否可删的唯一依据:在 Accessibility Inspector 中关闭 JS,刷新页面,再看该属性是否还影响 Computed Role 或 States。如果关闭 JS 后属性消失且无障碍行为未退化,那它大概率是运行时依赖项,不能删。



















