WAI-ARIA不是补救语义缺失的HTML,而是为动态内容和复杂控件提供补充语义的桥梁;用错role或乱加aria-*属性会让屏幕阅读器更困惑。必须用ARIA仅当原生HTML无法表达行为或状态时,如div模拟下拉菜单、span扮演按钮等;原生元素如button、nav、main不加role更安全。

直接说结论:WAI-ARIA 不是用来“补救”语义缺失的 HTML,而是为动态内容和复杂控件提供补充语义的桥梁;用错 role 或乱加 aria-* 属性,反而会让屏幕阅读器更困惑。
什么时候必须用 role 和 aria- 属性?
只有当原生 HTML 元素无法表达组件行为或状态时才需要。比如:div 模拟下拉菜单、span 扮演按钮、自定义滑块或树形控件。
- 原生
button、input[type="checkbox"]、nav、main等已有明确语义,不加role更安全 -
role="button"不能替代button—— 缺少内置键盘交互(空格/回车触发)、焦点管理、禁用状态处理 - 若用了
role="combobox",就必须配套实现aria-expanded、aria-haspopup、aria-controls和键盘导航逻辑
aria-live 该设成 polite 还是 assertive?
取决于更新是否打断用户当前操作。设错会导致语音被强行中断或关键提示被忽略。
-
aria-live="polite":适合非紧急反馈,如表单校验提示、搜索结果计数 —— 屏幕阅读器会在当前句读完后播报 -
aria-live="assertive":仅用于中断性信息,如错误弹窗、登录失败提示 —— 会立即中断当前语音并播报 - 避免对整个容器设
aria-live;应限定在最小变更区域,且每次只更新一个aria-live区域的内容 - 不要同时设
aria-live和role="alert"—— 后者已隐含aria-live="assertive"和aria-atomic="true"
为什么 aria-labelledby 比 aria-label 更可靠?
aria-label 是纯字符串,无法响应 DOM 变化;而 aria-labelledby 引用真实元素,支持动态更新和本地化。
立即学习“前端免费学习笔记(深入)”;
- 用
aria-labelledby="id1 id2"可拼接多个元素文本(按 ID 顺序),适合带图标+文字的按钮 -
aria-label在多语言场景下难维护;aria-labelledby可绑定data-i18n或 i18n 框架的实时翻译节点 - 注意:被引用的元素必须可访问(不能
aria-hidden="true",也不能display: none) - 不要用
aria-labelledby指向空元素或仅含 icon font 的span—— 屏幕阅读器会读出空字符串或字体名称
键盘交互没做全,ARIA 再规范也没用
ARIA 描述“是什么”,但不负责“怎么操作”。缺少键盘支持(Tab、Enter、方向键等)会让 ARIA 属性变成摆设。
- 自定义
role="tablist"必须实现:Tab 进出、左右箭头切换 tab、Enter/Space 激活、Home/End 跳转首尾 -
role="dialog"打开时需用inert或aria-hidden隐藏背景,且焦点必须 trap 在 dialog 内 - 所有交互控件都得有
tabindex="0"(或原生可聚焦);不可见但需聚焦的元素用tabindex="-1"+ JS 主动.focus() - 别忘了
onKeyDown中阻止默认行为(如event.preventDefault()对空格键),否则可能触发滚动或页面刷新
最常被跳过的其实是焦点管理 —— 很多团队花时间写 aria-expanded,却让下拉展开后焦点还停在触发按钮上。真正的辅助功能不是属性堆砌,而是把“用户如何到达、如何理解、如何操作”这三步走通。



















