aria属性必须在html原生语义无法表达组件行为或状态时精准补位;如自定义下拉需role="listbox"+aria-expanded+aria-activedescendant,模态框需role="dialog"+aria-modal="true"+aria-labelledby,动态内容区用aria-live="polite",且须js同步更新状态。

ARIA 属性不是“加了就无障碍”,而是要在 HTML 原生语义无法表达行为或状态时,精准补位——绝大多数场景,删掉 ARIA 反而更安全。
什么时候必须用 role 和 aria-*?
只有当原生标签做不到、且辅助技术需要知道「这是什么」和「现在是什么状态」时,才引入 ARIA:
-
role="listbox"+aria-expanded+aria-activedescendant:用于自定义下拉(div实现的非select) -
role="dialog"+aria-modal="true"+aria-labelledby:用于div模态框,缺一不可 -
aria-live="polite":仅用于动态插入内容区域(如无限滚动、表单提交成功提示),且要确保 DOM 是 append 而非 innerHTML 替换 -
aria-haspopup="menu":只加在触发按钮上,不能加在菜单容器本身;必须配合aria-expanded并由 JS 同步更新
哪些地方绝对不能加 ARIA?
强行覆盖原生语义,等于主动破坏读屏体验:
- 给
<button></button>加role="link"或role="switch"—— 它就是按钮,行为该由 JS 控制,不是靠改 role “伪装” - 给
<input type="checkbox">手动加aria-checked="true"—— 浏览器已自动同步,重复设置会导致状态不同步 - 给
<tr> 加 <code>role="search"—— 表格结构直接断裂,触发aria-requires-children报错 - 对整个导航栏或
加aria-hidden="true"来“隐藏背景”——正确做法是用inert属性或焦点锁定 - 有可见文本(比如图标旁写着“搜索”)→ 用
aria-labelledby="id-of-the-text" - 纯图标按钮、空按钮、隐藏控件 → 用
aria-label="搜索" - 别写
<button aria-label="提交">发送</button>—— “发送”会被静音,只读“提交” -
aria-labelledby支持跨元素组合,比如把图标id="icon"、说明文字id="desc"、输入框id="input"一起引用:aria-labelledby="icon desc input" -
aria-hidden="true"加在父容器上,子元素设aria-hidden="false"也无效(强制继承) - 给图标加
aria-hidden="true"是安全的,前提是旁边已有可见文字(如“用户名”+ 用户图标) - 不要和
display: none或visibility: hidden混用 —— 后两者本就会让读屏跳过,再加aria-hidden是冗余 - 真正需要“视觉隐藏但读屏可读”时,用
.sr-only类(position: absolute; clip: rect(0,0,0,0)),而不是aria-hidden="false"
aria-label 和 aria-labelledby 怎么选?
核心看「描述文本是否已在页面可见」:
aria-hidden="true" 的真实影响范围
它只对辅助技术生效,视觉用户照常看到,JS 照常操作 —— 这点被误用最多:
最常被漏掉的是键盘焦点流与 aria-live 的配合:模态框打开后没锁焦点,表单提交后提示没被播报,问题不在 ARIA 写没写,而在 JS 是否同步更新了状态、DOM 是否以辅助技术可感知的方式变动。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











