role属性是静态契约而非万能补丁:仅设role="dialog"或role="button"无效,必须配套aria-modal、aria-labelledby、焦点陷阱或tabindex、键盘事件监听、可访问名称及视觉反馈;原生语义元素不可覆盖;动态修改role不触发重计算,应改用aria-live。

role 属性不是“加了就完事”的语义补丁,它是一份静态契约:写了 role="dialog",辅助技术就认定这是对话框,但若没配 aria-modal="true"、没设 aria-labelledby、没管焦点,用户根本感知不到它存在。
role="button" 的 div 为什么按空格没反应
只写 role="button" 不等于按钮——它只是告诉读屏器“这玩意儿是按钮”,但没键盘支持、没焦点、没交互逻辑,等于贴了张假标签。
-
tabindex="0"必须加,否则不在 Tab 键流里,键盘用户根本碰不到 -
onclick和onkeydown都得监听:Enter 和 Space 键要触发相同行为,且必须调用event.preventDefault() - 必须提供可访问名称:靠可见文本,或显式加
aria-label/aria-labelledby - CSS 要定义
:focus和:active样式,否则视觉反馈缺失,键盘用户无法确认当前焦点在哪
role="dialog" 加了但屏幕阅读器不暂停主页面
仅设 role="dialog" 是无效声明。WAI-ARIA 1.1 明确要求模态框必须同时满足三项硬性条件,缺一不可。
-
aria-modal="true"是强制项(IE 不支持,需降级 fallback) -
aria-labelledby值必须指向一个真实存在、未被aria-hidden="true"或display: none隐藏的标题元素 ID - 焦点必须程序化 trap:打开时
focus()到第一个可交互子元素;Tab 键循环限制在弹窗内;关闭后focus()回触发按钮
哪些元素绝对不能加 role
原生标签已自带完整无障碍语义,强行覆盖会破坏辅助技术对 landmark 和状态的识别逻辑。
-
<button></button>已隐式含role="button",再加role="button"冗余,可能干扰焦点管理 -
<nav></nav>等价于role="navigation",写成<nav role="navigation"></nav>没意义,还暴露理解偏差 -
<input type="checkbox">自带role="checkbox"和自动同步的aria-checked,手动设aria-checked可能导致 JS 状态与 AT 状态不同步 -
<h1></h1>已有 heading 语义,加role="heading"不仅冗余,漏写aria-level还会让部分读屏默认 level=2
role 动态修改后为什么读屏没反应
role 是静态属性,辅助技术只在元素插入 DOM 时读取一次。运行时 JS 修改 role(比如从 role="button" 改成 role="alert"),不会触发语义重计算。
- 状态变化别改
role,改用aria-live区域配合文本更新更可靠 - 真要切换角色(极少见),应销毁旧元素、重建新元素并重新聚焦
- 检查是否在
display: none或visibility: hidden元素上设了role:这些元素本就不在可访问树中,设了也白设
最常被忽略的是:role 单独存在基本没意义。每个 role 都绑定一套最小语义契约,缺配套 aria- 属性或行为实现,就等于签了半份合同——辅助技术照着读,但什么都做不了。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











