role属性本身不提升可访问性,它仅是静态语义声明;真正起效需“role值+对应aria-*状态+实际交互行为”三者一致,单独添加role="button"却不处理键盘、焦点或视觉反馈,反而误导用户。

role 属性本身不提升可访问性,它只是一份静态语义声明;真正起作用的是「role 值 + 对应的 aria-* 状态 + 实际交互行为」三者一致。单独加 role="button" 却不处理键盘、焦点或视觉反馈,反而会让屏幕阅读器用户误以为能操作,结果按空格没反应——这比不加更糟。
为什么加了 role 读屏器还是没反应
因为辅助技术只在元素插入 DOM 时读取一次 role,后续 JS 修改(比如 element.setAttribute('role', 'alert'))不会触发语义重计算。常见失效场景包括:
- 动态插入弹窗后才加
role="dialog":必须在插入前就带好全部属性 - 用
display: none或visibility: hidden隐藏元素时设role:该元素根本不在可访问树中,设了也白设 - 父容器有
aria-hidden="true",子元素再设aria-hidden="false":继承强制生效,子元素仍不可访问
role="dialog" 必须配哪些属性才真正可用
仅写 role="dialog" 是无效声明,WAI-ARIA 1.1 明确要求三项硬性条件同时满足:
-
aria-modal="true"(IE 不支持,需 fallback 到aria-hidden手动控制背景) -
aria-labelledby指向一个真实存在、未被隐藏、有可见文本的标题 ID(不能是空<h2 id="title"></h2>) - 程序化焦点陷阱:打开时
focus()到第一个可交互子元素;Tab 键循环限制在弹窗内;关闭后focus()回触发按钮
哪些元素绝对不该加 role
原生语义已完备,强行覆盖会破坏辅助技术对 landmark 和状态的识别逻辑:
-
<button></button>已隐式含role="button",再加可能让旧版 NVDA 识别为“未知按钮” -
<nav></nav>等价于role="navigation",重复添加暴露理解偏差,还可能干扰 JAWS 解析 -
<main></main>自带role="main",手动添加不仅冗余,还可能让某些读屏跳过该 landmark -
<input type="checkbox">自动同步aria-checked,手动设会导致 JS 状态与 AT 状态不同步
最常被忽略的一点是:role 是契约,不是开关。它定义“这个元素是什么”,而不是“它现在正在做什么”。状态变化别改 role,该用 aria-live 区域配合文本更新来传达。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











