C01 无障碍与 ARIA

2026-10-31 14:510 阅读约 11 分钟HTML

摘要:无障碍不是额外功能,而是页面在「不用鼠标、不用屏幕」时的可用性下限。浏览器把 DOM 转成可访问性树,朗读软件与键盘导航都读这棵树;标签选错时这棵树会残缺,而 ARIA 只能补充语义,不能修复错误的标签。本文给出五条 ARIA 使用原则、一个可键盘走通的页面骨架,以及三项验证手段。
关键词:无障碍,可访问性树,ARIA,地标,焦点

所属:frontend/html / C-高级 | 上一篇:C00-总结 | 下一篇:C02-表单校验进阶

1 引言

页面在三种受限条件下会暴露问题:只用键盘、使用朗读软件、关闭动画与颜色。三者共同依赖同一棵树——浏览器根据 DOM 生成的可访问性树。

本文说明这棵树的来源、ARIA 的正确用法与验证方式。范围见表 1-1。

项 本文覆盖 本文不覆盖
语义 地标、标题、替代文本、表格关联 完整 WCAG 条款逐条对照
ARIA role、aria-label、aria-labelledby、aria-live、aria-expanded 复杂组件的状态机设计
键盘 焦点顺序、可见焦点、跳过链接 自定义组件的焦点陷阱实现
验证 无障碍面板、键盘遍历、朗读软件 自动化审计工具的规则库

2 预备知识

项 要求 核对方式
环境 A02 的本地服务器 能访问 localhost
文件 html-practice/a11y.html 编码 UTF-8
工具 Chrome 开发者工具无障碍面板(Elements → Accessibility) 能看到可访问性树
前置 A08、A07 语义骨架与表单可写

3 原理与实现

3.1 可访问性树的来源

浏览器把 DOM 中的语义换算成角色、名称与状态,辅助技术只读这份结果,如图 3-1 所示。

flowchart LR
    A["HTML 标签"] --> B["DOM 树"]
    B --> C["可访问性树<br/>角色 / 名称 / 状态"]
    C --> D["朗读软件<br/>按角色播报"]
    C --> E["键盘导航<br/>按可聚焦元素移动"]
    C --> F["浏览器阅读模式<br/>按地标提取正文"]

图 3-1 DOM 到可访问性树的换算

图上可见:角色由标签决定,名称由内容或标签关联补齐;div 在这棵树里既无角色也无名称,等同于不存在。

3.2 可键盘走通的骨架

<!-- 运行环境:Chrome 130+;body 内内容 -->
<a class="skip" href="#main">跳到正文</a>

<header>
  <nav aria-label="主导航">
    <ul>
      <li><a href="./index.html" aria-current="page">首页</a></li>
      <li><a href="#faq">常见问题</a></li>
    </ul>
  </nav>
</header>

<main id="main" tabindex="-1">
  <h1>无障碍检查清单</h1>

  <section id="faq">
    <h2>常见问题</h2>
    <details>
      <summary aria-expanded="false">为什么不能只靠颜色区分状态?</summary>
      <p>色觉差异人群无法分辨红绿,需要同时给出文字或图标。</p>
    </details>

    <p aria-live="polite" id="status">尚未提交。</p>
  </section>
</main>

<style>
  /* 焦点必须可见 */
  :focus-visible { outline: 2px solid #0f172a; outline-offset: 2px; }
  .skip { position: absolute; left: -999px; }
  .skip:focus { left: 1rem; top: 1rem; }
</style>

ARIA 的使用原则见表 3-1。

原则 说明 反例
能用原生标签就不用 ARIA 原生标签自带角色、键盘与状态 用 div role="button" 代替 button
不覆盖原生语义 给 button 加 role="link" 会造成混乱 同一元素两种角色
ARIA 只补不可见的语义 如无文字按钮的名称、动态区域的通知 用 ARIA 表达视觉样式
名称必须存在 交互元素的名称来自文字、标签或 aria-label 图标按钮无名称
状态必须随交互更新 展开、选中、当前页需要同步属性 面板展开了 aria-expanded 仍是 false

常用属性与用途见表 3-2。

属性 用途 使用场景
aria-label 给元素一个名称 无文字的图标按钮
aria-labelledby 引用页面上已有文字作为名称 弹层标题
aria-describedby 补充说明 输入框的错误提示
aria-live 动态区域播报(polite/assertive) 提交结果、加载状态
aria-expanded 展开状态 折叠面板、菜单
aria-current 当前项 导航中的当前页
aria-hidden="true" 从可访问性树中移除 纯装饰图标

4 验证与讨论

  1. 保存文件,刷新后只按 Tab 键遍历:第一个焦点应落在「跳到正文」,回车后焦点进入正文。
  2. 打开 Elements → Accessibility 面板,逐项核对导航、正文、按钮的角色与名称是否存在。
  3. 开启系统朗读功能,听取标题、导航与折叠面板的播报内容。
  4. 用取色工具把页面转为灰度,确认状态区分不依赖颜色。
检查项 预期结果 说明
跳过链接 Tab 首次聚焦可见,回车跳到正文 键盘用户可绕过导航
焦点可见 每个可聚焦元素都有明显描边 :focus-visible
地标 面板显示 header / nav / main 角色 语义标签生效
图标按钮名称 面板显示按钮名称 aria-label
动态播报 提交后朗读「已提交」 aria-live

讨论与局限。 ARIA 只能补语义,无法修复错误的交互实现;给 div 加 role="button" 后仍需自行处理回车与空格键。另 aria-live 区域初始必须是空的,先写内容再更新才可能被播报。

5 常见问题

现象 原因 处理
键盘无法到达某按钮 用 div 加点击事件,不可聚焦 改用 button,或补 tabindex="0" 与按键处理
朗读软件念出「按钮 按钮」 角色重复声明 删除多余的 role
弹层打开后朗读仍读背景 未设置 aria-hidden 或未用遮罩 背景加 aria-hidden="true"
状态变化无播报 动态区域初始已有内容 改为先清空再写入
跳过链接不可见 只做了位移隐藏,未处理聚焦样式 补 :focus 下的可见样式

6 结论

序号 结论 依据
1 辅助技术读可访问性树,标签决定角色与名称 图 3-1
2 原生标签优先,ARIA 只补不可见语义 表 3-1
3 交互元素必须有名称,状态必须同步 表 3-1
4 只用键盘走一遍是最低验证门槛 4 节步骤 1

参考文献

[1] WCAG 2.2 快速参考,W3C,https://www.w3.org/WAI/WCAG22/quickref/(访问于 2026-10-29)
[2] MDN Web Docs · ARIA,https://developer.mozilla.org/zh-CN/docs/Web/Accessibility/ARIA(访问于 2026-10-29)

返回文章列表

评论 0

0/2000

还没有评论,快来抢沙发吧~