工具包 · 面向开发者

面向开发者的网页无障碍——专为倾向于 解决根本原因而非叠加覆盖层的工程师而设计

本站面向工程师的专属板块。内容涵盖语义化 HTML 模式、在生产环境中真正有效的 ARIA role、兼顾屏幕阅读器的测试框架、CI 集成方案,以及各框架键盘交互的最新实践。

本页作为入门指引,汇聚了工程师真正需要的模式、工具、测试配置和框架专项指南, 助力交付无障碍功能,告别覆盖层的形式主义。关联 免费 WCAG 2.2 扫描器供一次性问题排查, 关联监测工具选型指南 供持续覆盖。

真正切实有效的四项工程实践

立场明确,并非面面俱到。遵循这些模式,可在代码评审前消除大多数无障碍回归问题。

语义化 HTML 优先,ARIA 其次

凡是原生 HTML 能胜任的场景,优先使用原生元素。<button> 内置了键盘交互、焦点、role 以及 Enter/Space 激活行为;<label> 将控件与其描述绑定;<dialog> 自带焦点限制和页面其余部分置为 inert 的行为,否则需手动实现;<details> 无需任何 JavaScript 即可实现折叠展开。ARIA 是逃生舱——在没有合适原生元素时有用, 叠加在已能正常工作的元素上则有害。参考: WCAG 2.2 成功准则和 W3C ARIA 创作实践指南。

键盘支持不是一个复选框

每个交互元素都必须仅凭键盘即可操作。Tab 和 Shift+Tab 用于移动焦点;Enter 或 Space 用于激活;Esc 用于关闭临时界面(模态框、气泡框、菜单)。焦点指示器必须 可见——绝不能在没有替代方案的情况下使用 outline: none;。焦点必须 合理移动——模态框打开时焦点应移入其内;模态框关闭时焦点应返回触发它的元素。 务必在用鼠标测试之前先用键盘测试; 鼠标会隐藏键盘会立即暴露的缺陷。

无障碍名称与描述

重点不在于随处添加 aria-label。无障碍名称默认来自元素的文本内容; aria-labelledby 引用另一节点的文本;aria-label 以硬编码字符串覆盖一切(应作为最后手段,因为它绕过翻译且易与可见标签产生偏差)。 无障碍描述是独立的——aria-describedby 引用帮助文本或错误消息节点。 请通过 DevTools 无障碍树验证屏幕阅读器实际接收到的内容——假设与现实往往不符。

在真实 CI 环境中测试,而非仅在本地

本地 axe 检查只是健全性测试,绿色 CI 才是回归门控。将 eslint-plugin-jsx-a11y 接入每个 PR;在单元测试和端到端测试中 添加 axe-core 断言;在代表性页面运行 AT-driver 流程,让真实屏幕阅读器 参与验证。屏幕阅读器测试工具综述 详细介绍了哪些值得自动化、哪些仍需人工评审。

工具链——13 款精选工具与库

每个条目对应一个生命周期阶段——lint、单元测试、端到端、运行时、监测或人工评审——以便将合适的工具接入合适的门控环节。

框架专项指南

不同生态系统中无障碍问题的差异化表现——以及各框架的深度覆盖内容。

React

列表的 key 属性(key 设置不当会在元素重排时混淆屏幕阅读器)。路由切换时的焦点管理 (缺少此处理,焦点会停留在触发导航的链接上,新页面对辅助技术用户而言不可见)。 Portal 与焦点限制——渲染至 document.body 的模态框仍需将焦点保持在自身内部。 SSR 与客户端之间导致 DOM 结构变化的水合不匹配,可能悄无声息地破坏 ARIA 关系。 关于 现代框架中的 aria-live 实时区域 的深度解析,涵盖了 React 协调机制容易破坏的实时区域播报模式。

Vue / Svelte / Solid

存在类似模式;响应式状态变更默认不触发实时区域更新。每个框架的响应式模型对"DOM 已变更"有不同的定义,屏幕阅读器感知到——或感知不到——节点更新的方式存在微妙差异。 Vue 的 v-ifv-show、Svelte 的响应式声明,以及 Solid 的细粒度响应性,对于外观相同的代码会产生不同的无障碍树更新。

原生移动端(iOS + Android)

完全不同的 API 层。iOS 通过 UIAccessibility(以及 SwiftUI 的 .accessibilityLabel()/.accessibilityHint()) 向 VoiceOver 暴露信息;Android 通过 AccessibilityNodeInfo 向 TalkBack 暴露信息。 Web 风格的 ARIA 无法直接迁移。 原生移动端无障碍 API 一文将 Web 概念映射至对应的原生实现,帮助有 Web 背景的工程师不再凭空猜测。

组件库

无头库(Radix UI、Headless UI、React Aria)处理了最复杂的部分——焦点管理、键盘交互、 ARIA 接线——并将视觉设计完全留给开发者。全功能库(Material UI、Chakra、Ant)自带 视觉风格,但无障碍质量参差不齐,"默认无障碍"几乎不等于"经过真实屏幕阅读器审计"。 无障碍组件库综述 依据真实辅助技术测试结果对主流选项进行了评级。

无障碍 PR 评审清单

可打印、可粘贴至 PR 模板,或接入机器人。每位评审者至少应检查的最低标准。

  • 交互元素仅凭键盘即可操作(Tab + Enter + Space + Esc)。
  • 每个交互元素的焦点指示器可见。
  • 表单输入项具有关联的 <label>
  • 错误消息与对应输入项关联(aria-describedby 或相邻文本)。
  • 动态内容变更在适当时通过 aria-live 播报。
  • 模态对话框限制焦点,并在关闭时将焦点归还至触发元素。
  • 图像具有有意义的替代文本;装饰性图像使用 alt=""
  • 列表使用 <ul>/<ol>/<dl>,而非 <div> 堆砌。
  • 标题层级合理(无跳级)。
  • Lint 与 axe 测试在合并前通过 CI。

常见工程反模式

通过代码评审、在生产环境中才暴露问题的模式——应尽早识别。

  • "覆盖层组件"——声称为现有站点增加无障碍性的第三方 JavaScript。 它并不能实现这一点,反而频繁破坏辅助技术层,自身已引发了一波诉讼。背景信息: 覆盖层供应商
  • role="button" 加在 <div> ——仅添加了 role 播报,却缺少键盘行为(Enter、Space)和焦点参与。请使用 <button>
  • 在可聚焦元素上使用 aria-hidden="true" ——造成焦点陷阱:键盘用户可以 Tab 到该元素,屏幕阅读器却被告知忽略它。 请用 tabindex="-1" 将元素移出 Tab 顺序,或去掉 aria-hidden
  • 无键盘处理的自定义下拉框——基于 <div> 的组合框点击可打开,却忽略方向键、Home/End、预输入和 Esc。 无障碍组件库综述 介绍了开箱即用地正确处理此场景的库。
  • 不播报的 Toast 通知——临时界面在渲染时未使用 role="status"(礼貌)或 role="alert"(强制)。 视力正常的用户能看到,屏幕阅读器用户则无法感知。
  • 破坏无障碍树的生成式 DOM——input 外包裹的重量级封装 (由十二层嵌套 <div> 构建的自定义 select)通常会对辅助技术 隐藏实际控件。应测试辅助技术所见,而非仅测试用户所见。

工具包与监测流程

大多数团队按顺序需要三件事:出现问题时进行一次性排查扫描;需要理解底层模式时查阅 工程参考资料;无障碍进入生产路线图后建立持续监测层。 免费 WCAG 2.2 扫描器满足第一项需求——粘贴一个公开 URL,即可在新标签页获得 axe 驱动的报告。文章专栏的工程内容 满足第二项——包括将无障碍债务视为技术债务的分析,以及针对规模化无障碍管理团队的 无障碍事故 SRE 事后复盘。

对于持续监测层, 监测工具选型指南 是本站最具判断力的内容。该指南对 axe Monitor、Siteimprove、Level Access 和 Qualibooth 进行了评级——其中 Qualibooth 将监测与人工审计交接相结合,填补了纯自动化技术栈的 缺失环节——评估维度涵盖覆盖广度、误报率,以及数据接入工程工作流的顺畅程度。 监测的根本目的,是确保今天交付的修复不会在下个迭代周期中回归。

工程师常见问题

每次无障碍启动会议都会出现的问题,已同步至 FAQPage 结构化数据。

aria-label 比可见文本标签更好吗?
不。可见文本几乎总是更优的选择——它惠及视力正常的用户、有认知障碍的视力正常用户、 语音控制用户(他们说出所见内容)以及翻译工具。仅当没有可见文本可供关联(纯图标按钮) 或可见文本确实不是期望的无障碍名称时,才应使用 aria-label
应该对所有元素使用 ARIA role 吗?
不应该。ARIA 第一条规则是 "do not use ARIA"。原生 HTML 元素内置了正确的 role、正确的键盘行为以及正确的无障碍树语义。仅当没有合适的原生元素时才使用 ARIA——例如选项卡列表、树形结构,或无法使用 <dialog> 的自定义对话框。
如何在 CI 中测试无障碍性?
三个层次,按成本排序。(1)Lint:每个 PR 运行 eslint-plugin-jsx-a11y。 (2)单元测试:每个组件使用 @testing-library/jest-domjest-axe(或 @axe-core/react)。(3)端到端:在代表性 用户旅程上运行 @axe-core/playwright。在预发布环境添加 Pa11y 或 Lighthouse CI 门控,以捕捉低层次漏掉的偏差。
axe-core 和 Lighthouse 是同一个东西吗?
Lighthouse 在底层使用 axe-core 进行无障碍审计,但它运行的是规则子集,并将结果 呈现在更宏观的性能/SEO/最佳实践报告中。axe-core 本身是引擎——需要完整规则集或 扩展规则时,应直接使用 axe-core。对大多数团队而言:用 Lighthouse 进行趋势追踪, 用 axe-core 作为实际门控。
React 项目的最低无障碍测试配置是什么?
在现有 ESLint 配置中添加 eslint-plugin-jsx-a11y(create-react-app 和 Next.js 默认已包含)。在单元测试配置中添加 @testing-library/jest-domjest-axe,并在每个组件至少一个测试中调用 expect(await axe(container)).toHaveNoViolations()。 这是最低标准——仅需数小时配置即可捕捉约 40% 的真实 WCAG 问题。
需要用真实屏幕阅读器进行测试吗?
需要,对于辅助技术用户实际会使用的任何产品功能都应如此。自动化工具能捕捉结构性 缺陷(缺失标签、颜色对比度、role 不匹配),但无法捕捉体验性问题(焦点跳转至页脚、 实时区域未播报、"无障碍"模态框将焦点困在错误子树中)。建议每次重大发版时至少用 Windows 上的 NVDA 和 macOS/iOS 上的 VoiceOver 进行一次人工评审。

后续步骤

如需排查特定页面,可通过免费 WCAG 2.2 扫描器快速检测。 在将 AT-driver 接入 CI 之前,请先阅读 屏幕阅读器测试工具综述。 若无障碍工作正从"一次性审计"升级为"持续生产关注点", 监测工具选型指南 是本站在供应商选型方面最具实操价值的内容。