关于 check-fix-accessibility
面向前端项目的无障碍审查与修复技能,默认优先处理 WCAG 2.2 A 和 AA。它结合自动化检查、人工复核、问题排序与修复后验证。
主要功能
- 01按 WCAG 2.2 A 和 AA 审查
- 02结合自动化工具与人工检查
- 03优先处理严重问题
- 04涵盖键盘、表单与语义问题
- 05修复后验证交互体验
适用场景
- 01审查网页的无障碍问题
- 02修复键盘操作和焦点缺陷
- 03检查表单标签及错误提示
- 04验证 SPA 路由切换后的焦点
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ neha/ check-fix-accessibility --skill check-fix-accessibility安装后在 Claude Code 中输入/check-fix-accessibility确认已加载。
附带文件frameworks.mdreference.md
详细介绍
检查并修复前端无障碍问题
系统性地审查并修复任何前端项目中的无障碍问题。除非用户另有指定,否则优先满足 WCAG 2.2 A 级和 AA 级。AAA 级为可选项:参见 reference.md。
版本与时效性:此技能有版本号(见上方的
version),并会根据last_reviewed日期所对应的特定标准进行审查。WCAG 和工具都在不断演进——依赖此技能前,请确认所依据的标准和固定的工具版本仍然有效;更新指南时,请同步更新version、last_reviewed和 Changelog。
适用范围
- Web(桌面端 + 移动 Web):全面适用。此技能适用于 HTML/CSS/JS、React、Next.js、Vue、Angular 和其他 Web 框架,包括响应式网页和 PWA。Next.js:使用
metadata或<Head>设置页面<title>;客户端导航应视为 SPA 路由变更——路由变更时更新焦点位置并播报(参见边缘情况)。各框架的标签、按钮、模态框和路由器代码片段:见 frameworks.md。 - 原生移动应用(React Native、Swift/Kotlin、Flutter):这些平台使用不同的 API 和模式(例如
accessibilityLabel、accessibilityRole)。请遵循相同原则(标签、焦点顺序、语义),但使用平台 API。相关指引见 reference.md。
快速工作流
- 审查 – 运行自动化检查和/或检查关键页面与组件。
- 确定优先级 – 优先处理严重阻碍和重大问题。
- 修复 – 按照下方模式应用修复;修改后再次检查。
- 验证 – 确认键盘操作流程;如有可能,确认屏幕阅读器行为。
运行审查
至少使用一种自动化工具;对重要流程还应结合人工审查。
固定工具版本以确保结果可复现。 将工具作为 devDependencies 安装,并指定确切版本(写入 package.json 和锁文件)。下列固定版本已于 2026-10-01 根据此技能中的代码片段进行检查。这并不表示更新的版本有问题。若较新的主版本会影响代码片段,则会在此处注明。
- Lighthouse(Chrome DevTools):运行无障碍审查。适用于整页快照。请在报告中注明 Chrome/Lighthouse 版本。
- axe DevTools(浏览器扩展或
@axe-core/cli、测试中的axe-core):按规则 ID 报告问题并进行修复。固定版本:npm i -D @axe-core/[email protected] [email protected]。 - pa11y(命令行):运行
npm i -D [email protected],然后执行npx pa11y <url>。pa11y 10 需要 Node^22.13.0或>=24。该命令与 9.1.1 相同,后者仍可在较旧的 Node 版本上运行。 - ESLint + 插件:
[email protected](React)、[email protected](Vue)。将它们加入 CI,并修复报告中的问题。
修复时,使用工具的规则 ID(例如 button-name、label、color-contrast)查找具体要求,并应用正确的修复方式。
测试渲染后的组件,而不只是已部署的 URL。优先使用角色和名称查询,而不是测试 ID。React、Vue 和 Angular lint 插件及各一个 axe 示例:见 frameworks.md。React 运行时细节(cypress-axe、Playwright):见 reference.md。
检查清单:常见问题与修复方式
复制此清单并用作进度列表。清单并不全面;请根据审查结果补充。
语义和结构
- 页面语言(3.1.1 A):在
<html>上设置lang。 - 页面标题:每个页面只有一个
<title>,内容描述准确且独一无二。 - 地标:使用
<main>、<nav>、<header>、<footer>、<aside>(或仅在无法使用这些元素时使用 ARIArole="main"等)。每个页面只有一个<main>。 - 标题(2.4.6 AA):标题文本应描述对应章节。跳过级别属于最佳实践问题,并非 2.4.6 的检查内容,也不会自动导致不符合 AA。
- 列表:列表内容使用
<ul>/<ol>/<li>;不要只用 div 和 CSS。 - 按钮与链接:执行操作(提交、打开模态框、切换状态)时使用
<button>。导航时使用<a href="...">。不要将<div>或<span>用作按钮或链接。 - 一致的帮助信息(3.2.6 AA):每个页面上的帮助信息都应保持相同的相对顺序。参见理由说明。
焦点和键盘
- 焦点可见(2.4.7 AA):每个交互元素都有可见的焦点指示器。不要在没有替代样式的情况下移除轮廓。
- Tab 顺序(2.4.3 A):DOM 顺序与视觉顺序一致。不要使用正数
tabindex。不存在aria-flowto属性。 - 无键盘陷阱(2.1.2 A):焦点始终可以移出;有意锁定焦点的模态框除外,但关闭时必须释放焦点。
- 可通过键盘操作(2.1.1 A):每种鼠标操作都应有键盘操作方式(Enter/Space,或使用可聚焦控件,而非仅支持悬停)。
- 焦点锁定:模态框打开时锁定焦点,关闭后将焦点返回触发控件。
- 跳过链接(2.4.1 A):“跳至主要内容”链接在获得焦点时可见,并将焦点移至
<main>。 - 焦点不被遮挡(2.4.11 AA):粘性页眉、页脚和横幅不会完全遮住获得焦点的元素。参见理由说明。
- 字符键快捷键(2.1.4 A,不属于 AA):可以关闭或重新映射单字符快捷键,或将其限制为控件获得焦点时才可用。
- 拖动的替代操作(2.5.7 AA):拖动操作也可通过点击、轻触或文本字段完成。
表单和标签
- 标签:每个控件都有
<label>(通过for/id关联或包裹控件),或使用aria-label/aria-labelledby。占位符不是标签。 - 标签包含在名称中(2.5.3 AA):可访问名称包含可见文本。
aria-label会替换内容,因此不要在已有可见标签的控件上使用它。 - 错误(3.3.1 A):错误应以可见文本呈现,不能只通过颜色或实时区域传达。使用
aria-describedby指向错误,设置aria-invalid="true",并在错误仍适用时将其保留在 DOM 中。 - 必填/选填:通过文本以及
aria-required或required属性标明必填字段。 - 分组:单选框和复选框组使用
<fieldset>和<legend>。 - 不可用的控件:
disabled会将控件从 Tab 顺序中移除。如果用户仍需将焦点移至该控件并了解其不可用原因,请使用aria-disabled="true"。 - 输入用途(1.3.5 AA):设置
autocomplete(如name、email、tel、street-address等)。 - 可访问的身份验证(3.3.8 AA):允许粘贴并支持密码管理器。不要将谜题或抄录内容设为唯一的登录方式。
- 避免重复输入(3.3.7 AA):在同一流程中不要再次询问相同信息。应自动填充或允许用户选择。
- 焦点或输入时不应意外改变页面状态(3.2.1 A、3.2.2 A):聚焦控件或在其中输入,本身不会改变上下文(提交、导航或打开新窗口)。
图像和媒体
- 替代文本:所有有意义的图像都应使用
alt描述其内容或功能。装饰性图像使用alt=""。 - 复杂图像:图表、示意图等应提供扩展说明(详细说明页面、
aria-describedby或可见文本)。 - 视频/音频:在适用时提供字幕和/或文字稿;确保控件可通过键盘访问且带有标签。
ARIA(当 HTML 不够用时)
- 角色:优先使用原生元素(button、link、heading 等)。仅为自定义控件添加 ARIA 角色(例如
role="dialog"、role="tablist")。 - 名称:交互元素和区域具有可访问名称:
aria-label、aria-labelledby或可见文本内容。 - 实时区域:对于需要播报的动态内容(提示消息、错误、更新),使用
aria-live、aria-atomic、aria-relevant。除非情况紧急,否则优先使用aria-live="polite"。 - 状态:使用
aria-expanded、aria-selected、aria-current等属性公开状态(展开/折叠、已选中、当前),并确保与 UI 保持同步。 - 避免:不要在本身已有相应语义的元素上使用
role/aria-*(例如在<button>上设置role="button")。尽量不要对可聚焦内容添加aria-hidden="true"。 - 悬停或聚焦时显示的内容(1.4.13 AA):工具提示可通过按 Escape 关闭、可悬停,并且会持续显示。请参阅原因。
- 状态消息(4.1.3 AA):不会移动焦点的结果(提示消息、“已保存”、表单错误)应通过实时区域传达。
颜色和对比度
- 对比度(1.4.3 AA):普通文本为 4.5:1,大号文本为 3:1。请参阅 reference.md。
- 非文本对比度(1.4.11 AA):有意义的图标和控件边界与相邻颜色的对比度至少为 3:1。
- 不能只依赖颜色(1.4.1 A):添加文本、图标或图案。颜色不能成为唯一提示。
- 强制颜色:不要依赖背景图像传达含义。请参阅原因。
动效和动画
- 暂停、停止、隐藏(2.2.2 A):持续超过 5 秒的移动、闪烁或自动更新内容可以暂停、停止或隐藏。
- 减少动效(2.3.3 AAA):对非必要动画遵循
prefers-reduced-motion: reduce。此项属于 AAA,而非 AA。
响应式布局和缩放
- 调整文本大小(1.4.4 AA):文本放大至 200% 时不会被裁切。不要设置
user-scalable=no,如果使用px锁定字体大小会导致文本被裁切,也不要这样做。 - 重排(1.4.10 AA):缩放至 400% 时,除确实需要二维滚动的内容(地图、表格、图表)外,不应出现二维滚动。这与 1.4.4 是不同的要求。
- 文本间距(1.4.12 AA):用户覆盖间距设置后,内容不会被裁切。请参阅原因。
- 触摸目标(2.5.8 AA):至少为 24×24 CSS px,或通过间距满足该标准。44×44 属于 AAA / 平台实践,并非 AA 的最低要求。请参阅 reference.md。
特殊情况和边缘情况
明确处理这些情况;自动化工具常常会漏掉它们。
屏幕阅读器
- 仅供屏幕阅读器使用的文本:当可见标签显得重复时(例如仅有图标的按钮),添加屏幕阅读器可见的标签(例如
.sr-only/aria-label),以便控件具有明确的名称。不要仅依赖title作为关键标签。 - 表格:数据表格使用
<table>、带有scope或headers的<th>,以及<caption>或aria-labelledby,以便屏幕阅读器用户能按单元格浏览。避免将表格用于布局。 - iframe:每个
<iframe>都需要描述性title(或aria-label),让屏幕阅读器用户了解该区域的内容。 - 链接用途(2.4.4 A):结合链接文本及其上下文(句子、列表项或单元格),链接用途应清晰明确。当上下文说明了目标位置时,“阅读更多”符合 A/AA 级要求。必须脱离上下文也能理解的链接文本属于 2.4.9 AAA 级要求,详见 reference.md。
- 重复播报:避免重复播报相同内容(例如
aria-label和可见文本表达相同内容;或多个实时区域播报同一次更新)。使用一个明确的信息来源。 - 内容语言:当元素中的内容使用与页面不同的语言时,使用
lang属性(例如<span lang="fr">),以便屏幕阅读器使用正确的发音。 - 播报顺序:确保实时区域和焦点移动不会导致顺序混乱(例如,在移除“正在加载”提示之前就播报结果)。加载期间使用
aria-busy,内容就绪后将其清除。
语音控制和 VoiceView
这是两种不同的工具。不要将 VoiceView 当作语音输入。
- 语音控制(Voice Access、macOS Voice Control、Dragon):用户会说出无障碍名称(“点击提交注册”)。名称必须简短且唯一。相比之下,应优先采用这种方式,而不是“第一个按钮/第二个按钮”。
- VoiceView(Amazon Fire OS 屏幕阅读器):它会像 TalkBack 一样朗读名称、角色和状态。它不是语音命令产品。测试流程:reference.md。
单页应用(SPA)和动态内容
- 路由/视图更改:导航时,更新
<title>,并将焦点移至主要内容或播报更改(例如使用aria-live="polite"区域,或将焦点移至<main>/标题),让屏幕阅读器用户知道页面已更改。跳过链接和<main>指向同一目标。React Router、Next.js、Vue Router 和 Angular:frameworks.md。React 焦点陷阱库:reference.md。 - 加载状态:在加载容器上使用
aria-busy="true",加载完成后将其设为false。也可以使用实时区域播报“正在加载……”,然后播报结果。 - 隐藏但可聚焦:隐藏内容(例如
display: none、hidden、非活动标签页面板)不得包含可聚焦元素,或者必须将这些元素从无障碍树中移除(例如在容器上设置aria-hidden="true",或在受支持的情况下使用inert)。否则,键盘/屏幕阅读器用户可能会聚焦到“不可见”元素。
其他
- 时间限制:如果内容有时间限制(会话超时、测验),请提供延长、关闭或调整时间限制的方式(WCAG 2.2)。
- CAPTCHA/验证:提供无障碍替代方案(例如音频 CAPTCHA、替代任务),并确保整个流程支持键盘和屏幕阅读器。
- RTL:对于从右向左书写的语言,在文档或容器上设置
dir="rtl"(或适当的dir),确保布局和阅读顺序正确。 - 第三方嵌入内容:如果嵌入了不受你控制的小组件或 iframe,请说明其应当具备无障碍支持,或提供替代方案(例如链接到其他位置的相同内容)。
修复模式(简明)
- 自定义控件:使用原生元素。如果无法使用,请添加
role、tabindex="0"(或由脚本管理焦点时使用-1)、可访问名称,以及 Enter/Space 键处理。 - 模态框:优先使用通过
showModal()打开的<dialog>。在当前浏览器中,它会锁定焦点。它不保证提供aria-modal;请为对话框添加aria-labelledby。自定义对话框需要添加role="dialog"、aria-modal="true"、aria-labelledby,将焦点移入其中、锁定焦点、支持按 Escape 关闭,并将焦点返回触发元素。 - 展开/收起:在触发元素上添加
aria-expanded和aria-controls;在面板上添加id;按 Enter/Space 时切换状态。 - 选项卡:使用
role="tablist"、role="tab"(带有aria-selected、aria-controls)和role="tabpanel"(带有id);使用方向键切换选项卡;按 Enter/Space 激活。 - 错误消息:在控件上添加
aria-describedby="id-of-error",无效时添加aria-invalid="true";确保错误元素具有id,并在无效时存在于 DOM 中。
提供反馈
报告问题时,请使用以下严重程度:
- 严重:阻断访问(例如,无法获得焦点、缺少标签、没有键盘操作路径)。优先修复。
- 较重:造成重大障碍(例如,对比度差、语义错误)。尽快修复。
- 轻微:改善体验(例如,多余的 ARIA、标题顺序)。条件允许时修复。
请包含:严重程度、文件或组件、元素或选择器、规则或指南,以及具体的修复方法。
示例
较重 — src/components/IconButton.tsx — button.icon-delete — axe button-name(4.1.2 名称、角色、值,A)。删除控件是一个没有可访问名称的纯图标 <button>。请添加 aria-label="Delete item" 或视觉隐藏文本。在此组件上重新运行 axe,并确认 button-name 问题已消失。然后按 Tab 移至该按钮,并使用 Enter 和 Space 激活它。
修复后
- 重新运行相同的审计工具,并确认违规项已消除或已作出说明。
- 仅使用键盘测试整个流程中的导航。
- 如果可能,使用一种屏幕阅读器(例如 NVDA、VoiceOver)测试已更改的组件。
参考
如需深入了解 WCAG 标准、ARIA 模式和组件示例,请参阅 reference.md。如果上方清单与 reference.md 存在重叠(例如对比度、目标尺寸、表格),请以 reference.md 为准——先更新它,再保持清单同步。
更新日志
- 1.8.0(2026-10-01):重新核对工具版本锁定,不再将 7 月的版本称为当前版本。axe CLI 和 axe-core 为 4.13.0,Vue ESLint 插件为 2.6.0,pa11y 为 10.0.0(Node 22.13+),jest-axe 为 11.0.0。
@testing-library/jest-dom仍使用 6.9.1,因为 7.0.1 仅与 Vitest peer 依赖兼容。路由焦点定位到应用外壳中的一个<main>,并跳过首次加载。Axe 示例调用expect.extend。上下文中的链接用途属于 2.4.4 A 级;脱离上下文的链接文本仍属于 AAA 级。标题 2.4.6 指的是描述,而不是大纲。新增 1.4.4 调整文本大小、3.3.1 可见错误、组合框模式、关于网站导航不是role="menu"的警告,以及原生模态框、装饰性图像和动态字体类型的说明。不再将showModal()描述为设置aria-modal。 - 1.7.0(2026-10-01):新增可选的 WCAG AAA 部分(7:1 对比度、增强版焦点不被遮挡、焦点外观、44×44 目标、仅凭链接文本判断链接用途、减少动态效果、增强版无障碍身份验证)。A 级和 AA 级仍为默认要求。新增可复制粘贴的
a11y:axe/a11y:pa11ynpm 脚本片段;此仓库不提供运行器。 - 1.6.0(2026-10-01):将单行屏幕阅读器说明替换为针对 NVDA、JAWS、VoiceOver、TalkBack 和 Amazon VoiceView 的通过/失败测试流程,其中包含用于移动和激活的手势。VoiceView 仍归类为屏幕阅读器;特别提及 Samsung Voice Assistant,以免将两者混淆。现在,视觉隐藏 CSS 片段确实会隐藏文本。
- 1.5.0(2026-10-01):新增
frameworks.md,其中包含 React、Vue 和 Angular 关于标签与 id、原生按钮、模态框(createPortal、<Teleport>、cdkTrapFocus/ CDK dialog)以及路由切换时焦点处理(React Router、Next.js、Vue Router、AngularNavigationEnd)的模式。Vue 和 Angular 的组件 axe 测试与现有的 React 测试放在一起。通用反模式仍保留在此文件中。 - 1.4.0(2026-10-01):修正检查清单的准确性:移除不存在的
aria-flowto属性;2.1.4 字符键快捷键属于 A 级,而非 AA 级;跳过标题属于最佳实践,不会自动导致 AA 不合格;新增 3.1.1 语言、2.5.3 标签名称一致、2.1.2 无键盘陷阱、1.4.11 非文本对比度、4.1.3 状态消息、2.2.2 暂停/停止/隐藏,以及 3.2.1/3.2.2。将prefers-reduced-motion标记为 2.3.3 AAA。优先使用<dialog>/showModal()。区分语音控制与 Amazon VoiceView。将较长的 WCAG 原理说明移至reference.md,并新增一份完整的问题报告示例。1.1.0–1.3.0 中的工具版本锁定保持不变。 - 1.3.0(2026-07-05):将检查清单中遗漏的 WCAG 2.2 AA 新成功标准补齐——2.4.11 焦点不被遮挡、2.5.7 拖动动作、3.2.6 一致的帮助、3.3.7 冗余输入、3.3.8 无障碍身份验证——以及 1.3.5 输入用途(
autocomplete)、1.4.13 悬停/焦点时显示的内容、2.1.4 字符键快捷键、1.4.12 文本间距和强制颜色/高对比度指南。在reference.md中列出所有 2.2 新增标准。将技能文件夹重命名为check-fix-accessibility,以匹配技能name和仓库,并注明reference.md是重叠指南的权威来源。 - 1.2.0(2026-07-04):新增 React 专属的
reference.md指南——“React 中的自动化测试”(jest-axe/vitest-axe、Testing Library 角色查询、cypress-axe /@axe-core/playwright,均已锁定版本)和“React 焦点与路由”(useEffect+ref 焦点处理、react-router、焦点陷阱库、React Aria/Radix/Headless UI 等无障碍原语);并从 SKILL.md 添加交叉引用。 - 1.1.0(2026-07-04):修正 WCAG 2.2 Recommendation 日期(2023 年 10 月;修订版为 2024 年 12 月);从 Robust 中移除已过时的 4.1.1 Parsing;明确目标尺寸(2.5.8 AA = 24×24 CSS px,44×44 属于 AAA/平台最佳实践);锁定工具版本并修正 Vue ESLint 插件包名;新增版本/last_reviewed 元数据和此更新日志。
- 1.0.0:初始技能(审计工作流、检查清单、边缘案例、修复模式、参考资料)。