better-accessibility

better-accessibility

热门

适用于产品界面的无障碍工程规范(Accessibility),涵盖焦点状态、键盘导航支持、ARIA 属性、表单交互及屏幕阅读器适配。当构建或审查 UI 组件、弹窗(modals)、菜单、表单、自定义控件,或者用户提出“做一下无障碍适配/无障碍优化”、反馈键盘导航或屏幕阅读器问题时使用。触发词包含 accessibility, a11y, WCAG, aria, focus ring, focus-visible, focus trap, keyboard navigation, tab order, tabindex, screen reader, sr-only, aria-live, alt text, hit area, touch target, prefers-reduced-motion, autoplay, toast duration, skip link, semantic HTML, aria-label, form errors, disabled buttons, "not keyboard accessible".

2405Star
72Fork
更新于 2026/7/29
SKILL.md
只读
名称
better-accessibility
描述

适用于产品界面的无障碍工程规范(Accessibility),涵盖焦点状态、键盘导航支持、ARIA 属性、表单交互及屏幕阅读器适配。当构建或审查 UI 组件、弹窗(modals)、菜单、表单、自定义控件,或者用户提出“做一下无障碍适配/无障碍优化”、反馈键盘导航或屏幕阅读器问题时使用。触发词包含 accessibility, a11y, WCAG, aria, focus ring, focus-visible, focus trap, keyboard navigation, tab order, tabindex, screen reader, sr-only, aria-live, alt text, hit area, touch target, prefers-reduced-motion, autoplay, toast duration, skip link, semantic HTML, aria-label, form errors, disabled buttons, "not keyboard accessible".

把无障碍做进 UI 手艺里(Interface Craft)

无障碍(Accessibility / a11y)不是最后阶段为了搞定合规才硬塞进来的勾选框,而是界面设计与工程手艺的底线。只要善用 Web 原生平台特性,绝大多数无障碍支持都是“免费”的:原生 HTML 元素自带键盘支持、真正的 Label 会自动向读屏软件朗读,而一个清晰可见的焦点环(Focus Ring)不过就是一行 CSS 的事。在编写或审查 UI 代码时,请贯彻以下原则;修复问题时,注意保持与项目现有的样式方案(Tailwind / 原生 CSS / CSS-in-JS)一致。

在做 UI 审查时,先以“纯键盘用户”的身份把整个界面走一遍(所有业务流程必须在不用鼠标的情况下顺利完成);然后再以“屏幕阅读器用户”的身份测试:每个控件是否都能清晰朗读出它的名称(Name)、角色(Role)和状态(State)?当不确定怎么选时,优先使用 Web 平台默认的元素而非手造控件;能不用 ARIA 就尽量不用,少加比乱加强。

渲染后的文本/背景对比度测量与颜色修复,请参考 better-colors Skill;视觉字号与 iOS 输入框缩放问题,请参考 better-typography;RTL 布局与空间布局,请参考 better-layout

快速参考

分类 适用场景
焦点与键盘导航 焦点环、跳过链接(Skip link)、tabindex、焦点捕获/锁死(Focus trapping)、APG 键盘交互模式
语义化与 ARIA 原生元素优先、Button 与 Link 的区分、地标元素(Landmarks)、可访问名称(Accessible names)、禁用状态
表单 Label 标签、自动补全(autocomplete)、错误提示、输入框类型
屏幕阅读器 视觉隐藏内容、动态区域(Live regions)、Toast 提示、Alt 文本、SVG 适配
点击/热区面积 目标尺寸、扩大热区、碰撞规则
动画与缩放 prefers-reduced-motion、自动播放与定时 UI、200% 页面缩放、流式重排(Reflow)、rem 与 px 选用

核心原则

1. 原生元素优先 (Native Elements First)

ARIA 的第一条法则:只要有原生 HTML 元素能用,就绝不要用 ARIA。按钮操作用 <button>,页面跳转用 <a href>(必须支持 Cmd/Ctrl/中键点击新标签页打开),严禁写 <div onClick>。没有 ARIA 远比写错 ARIA 强。

2. 焦点环清晰可见 (Visible Focus Rings)

针对 :focus-visible 样式化,而不是直接给 :focus 设样式,这样键盘操作时能看到焦点环,而鼠标点击时不会出现无谓的边框。优先使用浏览器默认未修改的焦点指示器。如果设计规范要求自定义焦点环,请使用项目统一的 focus token 或显式指定的颜色,并确保焦点指示器在其经过的每一种相邻背景色上都能看清;仅在确认对比度无误后方可使用 currentColor。焦点环应至少保持 2px 实线外边框或同等的显眼面积。切勿在没有替代方案的情况下写 outline: none,且在强制颜色模式(Forced-colors mode / 高对比度模式)下需保留系统配色。

3. 完整的键盘支持 (Full Keyboard Support)

每一个指针(鼠标/触控)交互都必须有对应的键盘操作路径,遵循 ARIA APG 设计模式:按 Escape 键关闭浮层/弹窗,方向键在复合控件内部移动(标签页 Tabs、菜单 Menus、列表框 Listboxes),Tab 键在不同控件间切换,Enter 和 Space 键触发激活。只允许使用 tabindex="0"(加入自然 Tab 焦点顺序)和 tabindex="-1"(仅支持代码编程聚焦),绝不要使用正数 tabindex(如 tabindex="1"),这会破坏自然的焦点流。复合控件需采用巡回焦点模式(Roving tabindex):当前激活项为 0,其余全为 -1

4. 捕获与恢复焦点 (Trap and Restore Focus)

模态弹窗(Modals)打开时,需为背景内容设置 inert 属性,并将焦点移入弹窗内部;弹窗关闭时,必须将焦点还给最初的触发按钮。添加 overscroll-behavior: contain 样式,防止滚动弹窗时连带背景一起滚动。

5. 最小热区面积 (Minimum Hit Area)

WCAG 2.5.8 AA 级的基线标准是 24×24 CSS 像素的目标尺寸,或符合其规定的间距、等效控件、内联文本、浏览器原生控件或必要例外。为了更轻松地点击,在密度允许的情况下,移动端/触控场景建议达到 44×44px,桌面端界面建议达到 40×40px。如果视觉上控件需要保持较小尺寸,可通过伪元素(如 ::after)扩展热区。切勿让扩展后的热区相互重叠。

6. 每一个控件都要有 Label 和正确的 Type

每个输入框都要配备 <label for> 或被 <label> 包裹;Placeholder(占位符)绝对不能当作 Label 使用;Label 和控件应共享同一个热区——复选框与其旁边文本之间不能有点击无效的死角。为输入框添加具有实际语义 nameautocomplete 属性,以及匹配键盘类型的 typeinputmode。切勿禁止粘贴;用户需要粘贴密码和一次性验证码。

7. 会主动朗读的错误提示 (Errors That Announce)

在提交请求发起之前,保持“提交”按钮处于可点击状态;发起请求后将其禁用并显示 Loading 圈,但要保留原本的文字 Label。在提交时进行表单校验:给校验失败的字段标注 aria-invalid="true",将 aria-describedby 指向内联的错误文案,并将焦点移至第一个不合格的输入框。仅在原生控件真正不可用时才使用原生 disabled。只有在刻意保留可聚焦性或可发现性时才使用 aria-disabled="true";此时须在代码中手动阻止指针、键盘和表单行为,并显式设置该状态的样式。

8. 随处可见的可访问名称 (Accessible Names Everywhere)

纯图标按钮必须配备描述性的 aria-label。界面上可见的 Label 文本必须包含在无障碍名称(Accessible Name)中。装饰性元素需加上 aria-hidden="true",但绝不能加在可聚焦的元素上。

9. 切勿单纯依赖颜色传达信息 (Don't Rely on Color Alone)

状态提示需要颜色以外的冗余视觉线索:比如配合图标、文字或下划线。根据内容和状态确定适用的 WCAG 对比度要求,然后使用 better-colors 测量渲染后的前景色/背景色对。当对比度不达标时,报告该颜色对及未达到的标准;除非用户明确要求,否则不要随意更改项目的配色方案。

10. 尊重 prefers-reduced-motion

将动画效果包裹在 @media (prefers-reduced-motion: no-preference) 中,使其成为渐进增强的选择。在开启“减弱动态效果”模式下,将位移/缩放动画替换为透明度渐变(Opacity Crossfade);彻底禁用视差滚动(Parallax)和视频自动播放。无论用户是否有此偏好:自动播放的媒体必须提供显式的暂停控件;带有操作按钮或错误信息的 Toast 提示必须保持显示,直到用户主动关闭。

11. 动态内容的朗读播报 (Announce Dynamic Content)

字段专属的校验提示使用 aria-describedby;与具体控件无关的非紧急更新(如 Toast 弹窗、搜索结果数量通知),使用温和的 Live Region(role="status");只有与控件无关的紧急错误才使用 role="alert"。为了实现可靠的重复温和播报,请在更新文本之前先渲染一个稳定的空区域;动态插入的 alert 在不同设备上支持度不同,必须在目标屏幕阅读器上进行实测。

12. 按用途撰写 Alt 文本 (Alt Text by Purpose)

装饰性图片使用 alt="";传达信息的图片描述其内在含义;功能性图片描述其对应的操作:比如搜索图标按钮的 Alt 应为 alt="搜索",而不是 alt="放大镜"

13. 良好结构即是高效导航 (Structure Is Navigation)

使用能准确描述对应章节并形成清晰大纲的标题;推荐的默认做法是单页面设置一个 <h1> 并按层级正确嵌套,但这并非 WCAG 的硬性通过/不通过规则。在页面中暴露一个可见的主内容区 <main> 地标。如果主内容前面有重复的导航或 Header,请将“跳过至主内容”(Skip to content)链接设为页面上的第一个可聚焦元素。带锚点的标题需设置 scroll-margin-top

14. 完美适配缩放与字号调整 (Survive Zoom and Text Resize)

页面在 200% 放大倍率以及 320px 宽度下必须能正常工作且实现流式重排,不得出现横向滚动条。在文本容器上使用 min-height 而不是固定的 height;在符合项目代码规范的前提下优先使用 rem 响应式断点;严禁写 user-scalable=nomaximum-scale=1

常见误区与修复方式

常见误区 正确修复方案
使用 outline: none 直接干掉焦点环 :focus-visible 设置样式;这样鼠标点击时不会显示焦点环,键盘操作时会显示
误以为自定义焦点颜色在任何背景下都能看清 在所有相邻背景色及强制颜色模式(高对比度模式)下验证完整的指示器对比度
使用 <div onClick> 充当按钮或链接 操作用 <button>,页面跳转用 <a href>
仅把 Placeholder(占位符)当作唯一的 Label 添加可见的 <label for>;用户输入内容后 Placeholder 会消失
使用正数 tabindex 来调整焦点顺序 修正 DOM 树中的节点顺序;tabindex 只使用 0-1
重复的温和更新提示播报不稳定/时灵时不灵 保持一个稳定的空 status 区域并更新其文本内容;在目标屏幕阅读器上实测
给常规 Toast 提示使用 assertive 级别的动态区域 使用 politeassertive 仅留给紧急错误提示
在可聚焦的元素上写了 aria-hidden="true" 移除该属性,或者使该元素不可聚焦
功能性图标的 Alt 文本在描述图片长相 描述其功能操作:用 alt="搜索",而不是 alt="放大镜"
使用 maximum-scale=1 来阻止 iOS 输入框自动放大 将移动端输入框字号设为至少 16px(参考 better-typography);绝不禁止用户缩放
表单未填完前禁用提交按钮 保持提交按钮可点击;在提交时触发校验并聚焦至第一个错误字段

审查输出格式 (Review Output Format)

仅当用户明确要求提供独立的无障碍审查报告时,才使用此格式。当由 better-interface 统筹审查时,请将本领域的证据与发现提交给该 Skill,由其输出格式、严重级标准、归并规则、上限及最终结论决定。

独立无障碍审查报告分为两个部分展示。

审查发现 (Findings)

按原则将所有已确认的问题分组。使用包含 Severity(严重程度)、Location(位置)、Before(修改前)、After(修改后)、Why(原因)列的 Markdown 表格。切勿拆分成多行“Before:”/“After:”。

  • Severity: HIGH(阻碍用户完成任务、对辅助技术隐藏内容、或造成系统性无障碍失效);MEDIUM(显著增加交互难度);LOW(局部细节打磨)。
  • Location: 引用 path/to/file:line。如果产物没有源码文件,则引用具体的页面和组件名称。
  • Before / After: 展示当前实现以及可执行的替换方案。
  • Why: 说明违反的原则及其对用户体验造成的影响。

将重复出现的系统性问题合并为一行,并列出所有受影响的位置。无问题的原则直接省略。

示例

随处可见的可访问名称
Severity Location Before After Why
HIGH src/Dialog.tsx:42 <button><XIcon /></button> 添加 aria-label="关闭"; 图标加上 aria-hidden="true" 纯图标控件缺失可访问名称
HIGH src/Nav.tsx:18 <a href="/settings"><GearIcon /></a> 添加 aria-label="设置" 屏幕阅读器无法获知链接跳转目标
焦点环清晰可见
Severity Location Before After Why
HIGH src/button.css:12 button:focus { outline: none; } button:focus-visible { outline: 2px solid; outline-offset: 2px; } 键盘用户无法看到当前焦点位置
HIGH src/Menu.tsx:31 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 菜单键盘导航缺乏可见的焦点指示器
会主动朗读的错误提示
Severity Location Before After Why
HIGH src/EmailField.tsx:27 仅靠 border-red-500 标红显示错误 添加 aria-invalid="true" + aria-describedby="email-error" 关联内联错误文本 仅靠颜色既无法解释错误,也无法自动朗读
MEDIUM src/SignupForm.tsx:64 表单合规前禁用提交按钮 保持提交按钮可点击;失败时聚焦第一个无效字段 禁用按钮会隐藏需要修正的内容
最小热区面积
Severity Location Before After Why
MEDIUM src/Toolbar.tsx:22 size-4 纯图标按钮 使用 after:absolute after:size-11 将热区扩展至 44×44px 目标尺寸太小,高频触控容易误操作

验证与结论 (Verification and Verdict)

在审查发现之后:

  1. 验证 (Verification):列出具体执行的检查项及其观测结果,包括键盘遍历测试、可访问名称检查,以及适用的屏幕阅读器或自动化工具检查。若某项检查未执行,请注明仍需验证的内容。
  2. 结论 (Verdict)