Communitygithub.com

前端可访问性

在构建或维护任何交互式组件、表单、对话框或页面时使用。强制执行 WCAG 2.1 AA 标准——首选语义化 HTML,仅在语义不足时使用 ARIA,支持完整的键盘操作、可见焦点、对比度、带标签的输入以及尊重运动偏好。在添加模态框、构建下拉菜单、表单验证、键盘导航、屏幕阅读器、对比度、可访问性审计时触发。

前端可访问性 是什么?

该技能为 AI 助手(如 Claude Code、Cursor、Codex)提供一套完整的规则和模式,用于构建符合 WCAG 2.1 AA 标准的前端可访问性。它强调“语义化 HTML 优先”原则,仅在 HTML 无法满足语义时使用 ARIA 属性,并严格禁止使用 ARIA 覆盖元素已有的语义。覆盖了键盘操作、颜色对比度、图像和媒体替代文本、表单标签和错误处理、目标大小(触控表面使用 44×44 CSS 像素作为基准)、运动偏好(`prefers-reduced-motion`)以及自动测试。对于用户界面组件,它还提供了具体的实现模式,如按钮、表单输入、对话框、列表框和跳过链接。该技能要求所有交互元素必须可通过 Tab 键聚焦,焦点必须始终可见,并且颜色不能作为传达信息的唯一方式。它适用于任何包含 `<ui-packages-dir>` 和 `<web-dir>/src/` 下页面的项目,并鼓励通过项目特定的 `STACK-PROFILE.md` 文件解析具体的实现约定。

兼容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/chandra-pangea/plugin-ax-ai-ts-full-stack/tree/HEAD/claude/skills/frontend-accessibility

在你喜欢的 AI 中提问

打开一个已预加载此 Agent Skill 的新对话。

文档

前端可访问性 是做什么的?

适用于 <ui-packages-dir> 中的组件和 <web-dir>/src/ 下的页面。目标是 WCAG 2.1 Level AA,这是一个底线而非目标。

解决项目约定

尖括号中的值来自项目的技术栈配置文件。按以下顺序解析它们:

  1. 读取仓库根目录下的 STACK-PROFILE.md 并直接使用其中的值。
  2. 如果该文件不存在或缺少某个键,则从仓库中推断——从 Web 应用程序的依赖关系中推断 css-strategy 和 ui-framework。
  3. 如果仍然无法解析,则匹配仓库中已经存在的约定。
  4. 仅当仓库为空时,退回到本技能声明的默认值——然后将选定的值写入 STACK-PROFILE.md。

切勿在仓库已表达出一种约定时发明新的约定。


硬性规则

1. 语义化 HTML 优先

  • 使用 <button> 表示操作,<a> 表示导航。绝不要使用 <div> 并添加点击处理程序。
  • 标题级别向下递减,不得跳级。
  • 每个表单字段都必须有 <label>,并通过 htmlFor 属性关联。
  • 使用 <fieldset> 和 <legend> 对表单控件进行分组。
  • 每个页面都应有地标元素 —— <nav>、<main>、<footer>、<aside>。

2. 仅在 HTML 无法满足语义时使用 ARIA

优先级顺序是:语义元素,然后是 ARIA 属性,最后是自定义行为。切勿使用 ARIA 覆盖元素已经携带的语义——在 <div> 上使用 role="button" 是糟糕地重新实现了 <button> 免费提供的功能。

错误的 ARIA 比没有更糟糕:错误的 aria-label 会静默地替换屏幕阅读器本应正确计算出的可访问名称。

3. 键盘操作是强制性的

  • 所有可交互元素都必须可通过 Tab 键聚焦。
  • Tab 顺序应遵循视觉顺序。
  • 焦点必须始终可见。切勿在未替换轮廓线的情况下移除轮廓线。
  • Escape 键关闭对话框和弹出窗口;Enter 和 Space 键激活控件;箭头键在复合小部件内移动。
  • 自定义小部件要显式管理焦点。

4. 颜色和对比度

  • 正常文本对比度 4.5:1,大文本(18px 或 14px 粗体)和重要的 UI 边界对比度 3:1。
  • 颜色不能单独传达信息——必须配合文本、图标或图案使用。
  • 需要同时检查两种主题,而不仅仅是默认主题。

5. 图像和媒体

  • 每张图片都必须有 alt 属性。内容图片需提供描述性文本,装饰性图片使用 alt=""。
  • 永远不要使用“图片”、“照片”或文件名作为替代文本。
  • 复杂图片需要通过 aria-describedby 或图注提供长描述。
  • 视频需提供字幕,音频需提供文字转录。

6. 表单

  • 每个输入框都必须有标签。
  • 错误信息通过 aria-describedby 关联,并使用 role="alert" 进行宣告。
  • 无效字段需标记 aria-invalid。
  • 必填字段使用 required 属性——如果显示星号,则必须在某处用文本说明其含义。
  • 提交失败时,焦点应移动到第一个无效字段。

7. 目标大小

WCAG 2.1 AA 没有规定最小目标大小(2.2 AA 设定为 24×24 CSS 像素;44×44 是 2.1 AAA 以及平台 HIG 约定)。对于触控表面上的主要操作,将 44×44 视为最低标准,并按如下方式应用:

  • 主要操作、危险操作以及用户在手机上可能够到的任何元素:44×44。
  • 密集的桌面界面元素——工具栏、表格行操作、紧凑的表单控件——可以缩小到 24×24,前提是这些目标不与其他目标相邻,并且其他地方存在等效的全尺寸控件。
  • 间距很重要。一个 32px 的控件,每边有 6px 的清晰间距,满足 2.2 标准;一个 32px 的控件紧挨着相邻控件则不满足。

第三方组件库通常低于此标准——默认按钮高度为 32 或 36 CSS 像素很常见。不要手动编辑第三方文件来修复,也不要默认接受这种不匹配。在 <wrappers-pkg> 中提高默认值,以便每个消费者都继承合规的大小,同时保留较小的尺寸作为明确的选择,用于密集布局。这样,可访问的选择就是你无需思考就能得到的那个。

在 STACK-PROFILE.md 中记录项目采用了哪种解决方案。未声明的豁免会被每六个月作为一个错误重新发现一次。

8. 运动

  • 尊重 prefers-reduced-motion。
  • 自动播放的内容需要有暂停控制。
  • 任何内容的闪烁频率不得超过每秒三次。

9. 测试是工作的一部分

  • 仅使用键盘操作该功能。
  • 使用屏幕阅读器测试——macOS 上的 VoiceOver,Windows 上的 NVDA。
  • 在端到端测试套件中运行自动化扫描。

自动化工具约能捕获三分之一的实际问题。它们是底线,不是通过标准。


模式

完整的实现位于 references/component-patterns.md。每个模式保证以下内容:

  • 按钮——一个语义化的 <button>,其焦点环仅对键盘用户显示(focus-visible),包含符合运动偏好的过渡动画,并提供 ariaLabel 属性用于纯图标按钮。
  • 表单输入——一个带标签的输入框,其错误文本通过 aria-describedby 程序化连接,使用 role="alert" 宣告,并标记 aria-invalid;必填星号带有 aria-hidden。
  • 对话框——使用 showModal() 方法实现的原生 <dialog>,可免费获得焦点陷阱、Escape 键处理以及 inert 背景;打开时焦点移入,关闭时焦点恢复到触发元素。
  • 列表框——一个自定义选择组件,具有循环箭头键导航和正确的 ARIA 绑定(aria-activedescendant、role="listbox");仅在原生的 <select> 不适用时才构建它。
  • 跳过链接——允许键盘用户跳过导航,仅在聚焦时可见;目标元素拥有 tabIndex={-1} 以确保焦点真正落在那里。

WCAG 快速参考

原则要求实践中
可感知内容对每种感官都可用替代文本、字幕、颜色加图标
可操作一切都可以通过键盘到达Tab 顺序、Escape 关闭、焦点可见
可理解可预测且措辞清晰一致的导航、平实的语言
健壮与辅助技术兼容有效的 HTML、正确的 ARIA、语义元素
问题修复
未标记的输入框添加 <label htmlFor>
对比度低满足 4.5:1,或大文本 3:1
缺少键盘路径使用真正的交互元素,管理焦点
缺少替代文本提供描述,或装饰性图片使用 alt=""
仅靠颜色传达意义添加文本或图标
纯图标按钮添加 aria-label
闪烁内容保证每秒少于三次闪烁

运动偏好

在纯 CSS 中处理减少运动。像 motion-safe: 这样的工具类变体仅在允许运动时应用,因此将其放在减少运动查询内会生成一条永远无法匹配的规则。

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

使用接近零而非 none 可以保持过渡结束事件触发,从而避免等待这些事件的组件挂起。

对于按组件的控制,将 motion-safe: 变体直接应用于动画工具属性本身——例如上面的按钮中使用的 motion-safe:transition-colors。

视觉隐藏内容

大多数工具框架已经提供了 sr-only 和 not-sr-only 类。直接使用它们,不要重新定义。如果你的框架没有,参考实现位于 references/component-patterns.md。


测试清单

键盘

  • 每个交互元素均可通过 Tab 键聚焦
  • Tab 顺序与视觉顺序匹配
  • 焦点始终可见
  • Escape 键关闭对话框和弹出窗口
  • 箭头键在复合小部件中正常工作
  • 对话框关闭时焦点返回到触发元素

屏幕阅读器

  • 所有内容均可访问
  • 无需周围上下文即可了解控件用途
  • 标签与其字段一起宣告
  • 错误通过 role="alert" 宣告
  • 存在地标
  • 装饰性元素使用 aria-hidden 隐藏

颜色

  • 正常文本 4.5:1,大文本和 UI 边界 3:1
  • 没有仅靠颜色传达信息的情况
  • 两种主题均已验证

运动

  • 遵循减少运动设置
  • 无超过每秒三次的闪烁
  • 自动播放内容可暂停

自动化

扫描在 Playwright 套件中运行——参见 frontend-testing。Axe-in-Playwright 代码片段位于 references/component-patterns.md。

参考文档

深入探讨参考
可访问组件实现:按钮、表单输入、模态框、列表框、跳过链接references/component-patterns.md

相关技能

  • frontend-architecture —— 组件分层和主题化
  • frontend-testing —— 这些检查运行的地方
  • frontend-component-docs —— 记录组件的可访问性契约

相关技能