ARIA 无障碍访问
约 987 字大约 3 分钟
布欧-Lewyon
2026-05-16
WAI-ARIA(Web Accessibility Initiative - Accessible Rich Internet Applications)是一组 HTML 属性,帮助屏幕阅读器和其他辅助技术理解页面的结构和交互。
残障用户如何浏览网页
| 残障类型 | 使用的辅助技术 | HTML 要求 |
|---|---|---|
| 视觉障碍 | 屏幕阅读器(NVDA、VoiceOver) | 语义化标签、alt 文本、ARIA |
| 行动障碍 | 键盘导航(Tab / Enter / 方向键) | 可聚焦元素、Tab 顺序 |
| 听力障碍 | 无(视觉信息需补充文字) | 字幕 <track>、文本替代 |
ARIA 的黄金法则
第一原则:优先使用原生 HTML 语义。不要用 ARIA 来"修复"错误的 HTML。
<!-- ❌ 错误:用 ARIA 模拟按钮 -->
<div role="button" tabindex="0" onclick="submit()">提交</div>
<!-- ✅ 正确:直接用 <button> -->
<button type="submit">提交</button>第二原则:不要改变原生语义。原生
<a>就是链接,不要给它加role="button"。
<!-- ❌ 错误 -->
<a href="/" role="button">首页</a>
<!-- ✅ 如果是按钮就用 <button> -->
<button>首页</button>ARIA 三大支柱
1. role(角色)
告诉辅助技术"这是什么元素":
<nav role="navigation">...</nav>
<div role="alert">操作成功</div>
<div role="tabpanel">选项卡内容</div>
<div role="dialog">对话框</div>
<!-- 当原生元素不够用时 -->
<ul role="tablist">
<li role="tab" aria-selected="true">标签1</li>
<li role="tab">标签2</li>
</ul>
<div role="tabpanel">内容1</div>2. aria-* 属性(状态和属性)
描述元素的当前状态:
| 属性 | 作用 |
|---|---|
aria-label | 给元素提供文字标签(替代显示文本) |
aria-labelledby | 引用另一个元素的 id 作为标签 |
aria-describedby | 引用另一个元素的 id 作为详细描述 |
aria-hidden | 从无障碍树中隐藏(true / false) |
aria-expanded | 展开状态(true / false) |
aria-selected | 选中状态(true / false) |
aria-current | 当前项(page / step / location / date / time / true) |
aria-live | 实时区域更新通知(off / polite / assertive) |
aria-required | 必填字段 |
aria-invalid | 输入验证失败 |
aria-disabled | 禁用状态(比 disabled 属性更灵活) |
3. 键盘交互
自定义交互组件必须支持键盘操作:
| 组件 | 键盘行为 |
|---|---|
| 按钮 | Enter / Space 触发 |
| 链接 | Enter 触发 |
| 选项卡 | Tab 进入区域,方向键切换标签 |
| 下拉菜单 | Enter 打开,方向键导航,Escape 关闭 |
| 模态框 | Tab 循环焦点,Escape 关闭 |
| Tree | 方向键导航,展开/收起 |
常见 ARIA 模式
模态对话框
<div role="dialog" aria-labelledby="dialog-title" aria-modal="true">
<h2 id="dialog-title">确认删除</h2>
<p>此操作不可撤销,确定继续吗?</p>
<button onclick="closeDialog()">取消</button>
<button onclick="confirmDelete()">确定</button>
</div>加载状态
<div aria-busy="true">
<!-- 数据加载中... -->
</div>实时区域
<!-- 屏幕阅读器会朗读区域内容变化 -->
<div aria-live="polite" aria-atomic="true">
购物车中有 {{ count }} 件商品
</div>
<!-- 重要提示(立即朗读) -->
<div aria-live="assertive" role="alert">
表单提交失败,请重试
</div>错误提示
<label for="email">邮箱</label>
<input
id="email"
type="email"
aria-required="true"
aria-invalid="true"
aria-describedby="email-error"
>
<span id="email-error" role="alert">请输入有效的邮箱地址</span>实战:无障碍导航
<nav aria-label="主导航">
<ul>
<li><a href="/" aria-current="page">首页</a></li>
<li><a href="/blog">博客</a></li>
<li>
<a href="/products" aria-expanded="false"
onclick="toggleSubmenu(event)">产品</a>
<ul aria-label="产品子菜单">
<li><a href="/product-a">产品A</a></li>
<li><a href="/product-b">产品B</a></li>
</ul>
</li>
</ul>
</nav>小结
| ARIA 概念 | 作用 | 优先级 |
|---|---|---|
role | 定义元素角色 | 优先用原生语义标签 |
aria-label / aria-labelledby | 标签文本 | 所有可交互元素 |
aria-describedby | 详细描述 | 表单输入、对话框 |
aria-live | 实时区域更新 | 动态内容区域 |
aria-expanded / aria-selected | 状态信息 | 可展开/选择组件 |
| 键盘操作 | Tab / 方向键 / Enter | 自定义交互组件 |
上一节:iframe 与跨域通信 下一节:HTML 性能优化
