better-accessibility
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseAccessibility that comes with the craft
融入开发工艺的无障碍设计
Accessibility is not a compliance checkbox bolted on at the end; it is the floor for interface craft. Most of it is free if you use the platform: native elements ship with keyboard support, real labels announce themselves, and a visible focus ring is one CSS rule. Apply these principles when building or reviewing UI code, and match the project's existing styling system (Tailwind vs. plain CSS vs. CSS-in-JS) when applying fixes.
When reviewing, walk the interface as a keyboard-only user first (every flow must complete without a mouse), then as a screen-reader user: does each control announce a name, a role, and its state? When unsure, prefer the platform default over a custom rebuild, and remove ARIA rather than add it.
Contrast math (APCA thresholds, fixing contrast in OKLCH) is covered by the skill; text sizes, iOS input zoom, and RTL are covered by the skill.
better-colorsbetter-typography无障碍设计不是项目末期才匆匆补上的合规检查项,而是界面开发工艺的基础要求。只要合理利用原生平台能力,大部分无障碍特性都能轻松实现:原生元素自带键盘支持、真实标签会自动播报、只需一行CSS规则就能添加可见焦点环。在构建或审查UI代码时遵循这些原则,修复问题时要匹配项目现有的样式系统(Tailwind、纯CSS或CSS-in-JS)。
审查时,先以纯键盘用户的视角遍历界面(所有流程都必须无需鼠标即可完成),再切换到屏幕阅读器用户视角:每个控件是否会播报名称、角色和状态?不确定时,优先使用平台默认实现而非自定义重构,能移除ARIA就不要添加。
对比度计算(APCA阈值、OKLCH对比度修复)由技能覆盖;文本尺寸、iOS输入缩放和RTL布局由技能覆盖。
better-colorsbetter-typographyQuick Reference
快速参考
| Category | When to Use |
|---|---|
| Focus & Keyboard | Focus rings, skip links, tabindex, focus trapping, APG keyboard patterns |
| Semantics & ARIA | Native elements first, button vs link, landmarks, accessible names, disabled states |
| Forms | Labels, autocomplete, error messaging, input types |
| Screen Readers | Visually hidden content, live regions, toasts, alt text, SVG |
| Hit Areas | Target sizes, expanding hit areas, collision rules |
| Motion & Zoom | |
| 分类 | 使用场景 |
|---|---|
| 焦点与键盘 | 焦点环、跳转链接、tabindex、焦点捕获、APCA键盘交互模式 |
| 语义化与ARIA | 优先使用原生元素、按钮与链接的区别、地标区域、无障碍名称、禁用状态 |
| 表单 | 标签、自动填充、错误提示、输入类型 |
| 屏幕阅读器 | 视觉隐藏内容、实时区域、提示框、替代文本、SVG |
| 点击区域 | 目标尺寸、扩展点击区域、碰撞规则 |
| 动效与缩放 | |
Core Principles
核心原则
1. Native Elements First
1. 优先使用原生元素
The first rule of ARIA: don't use ARIA when a native element exists. for actions, for navigation (it must support Cmd/Ctrl/middle-click), never . No ARIA is better than bad ARIA.
<button><a href><div onClick>ARIA的第一条规则:有原生元素可用时,不要使用ARIA。用实现操作,用实现导航(必须支持Cmd/Ctrl/中键点击),绝对不要用。没有ARIA比错误使用ARIA更好。
<button><a href><div onClick>2. Visible Focus Rings
2. 可见焦点环
Style , not bare , so keyboard users get a ring and mouse users don't. The browser's default ring () renders the focus color the user configured in their OS and browser; prefer keeping it and only adding . If the design needs a custom ring, use with no color (it renders , never a hardcoded brand color) at contrast against adjacent colors. Never without a visible replacement.
:focus-visible:focusoutline-style: autooutline-offset: 2pxoutline: 2px solidcurrentColor3:1outline: none样式化而非裸用,这样键盘用户能看到焦点环,鼠标用户则不会。浏览器默认焦点环()会渲染用户在系统和浏览器中配置的焦点颜色;建议保留默认样式,仅添加。如果设计需要自定义焦点环,使用且不指定颜色(会渲染,绝不要硬编码品牌色),且与相邻颜色的对比度需达到3:1。绝对不要在没有可见替代方案的情况下使用。
:focus-visible:focusoutline-style: autooutline-offset: 2pxoutline: 2px solidcurrentColoroutline: none3. Full Keyboard Support
3. 完整键盘支持
Every pointer interaction needs a keyboard path, following the ARIA APG patterns: Escape closes overlays, arrow keys move within composite widgets (tabs, menus, listboxes), Tab moves between widgets, Enter and Space activate. Only (join the natural tab order) and (programmatic focus), never positive values, which break the natural order. Composite widgets use roving tabindex: the active item is , all others .
tabindex="0"tabindex="-1"0-1所有指针交互都必须有对应的键盘操作路径,遵循ARIA APG模式:Esc键关闭弹窗、箭头键在复合组件(标签页、菜单、列表框)内移动、Tab键在组件间切换、Enter和Space键触发操作。仅使用(加入自然Tab顺序)和(程序化聚焦),绝对不要使用正值,否则会破坏自然顺序。复合组件使用漫游tabindex:当前激活项设为,其余项设为。
tabindex="0"tabindex="-1"0-14. Trap and Restore Focus
4. 捕获并恢复焦点
Modals set on the background content, move focus inside on open, and return focus to the trigger on close. Add so background content doesn't scroll.
inertoverscroll-behavior: contain模态框需为背景内容设置属性,打开时将焦点移至框内,关闭时将焦点返回至触发按钮。添加防止背景内容滚动。
inertoverscroll-behavior: contain5. Minimum Hit Area
5. 最小点击区域
Interactive elements need a 44×44px hit area for touch or mobile contexts, at least 40×40px on desktop; WCAG 2.5.8's hard floor is 24×24px. Extend with a pseudo-element if the visible element is smaller. Never let hit areas of two elements overlap.
交互元素在触摸或移动场景下需要44×44px的点击区域,桌面端至少40×40px;WCAG 2.5.8的硬性标准是24×24px。如果可见元素尺寸更小,可通过伪元素扩展点击区域。绝对不要让两个元素的点击区域重叠。
6. Label and Type Every Control
6. 为每个控件添加标签和类型
Every input gets a or wrapping ; a placeholder is never a label, and label and control share one hit target: no dead zones between a checkbox and its text. Add with a meaningful , and the correct and for the keyboard. Never block paste; users paste passwords and one-time codes.
<label for><label>autocompletenametypeinputmode每个输入框都要有或包裹式;占位符永远不能替代标签,且标签与控件需共享同一个点击目标:复选框与其文本之间不能有无效区域。添加带有效的属性,并为键盘设置正确的和。绝对不要阻止粘贴操作;用户常会粘贴密码和一次性验证码。
<label for><label>nameautocompletetypeinputmode7. Errors That Announce
7. 可播报的错误提示
Keep submit enabled until the request starts, then disable with a spinner while keeping the original label. Validate on submit: mark failing fields with , point at the inline error text, and focus the first invalid field. Use native when a native control is genuinely unavailable. Use only when retaining focusability or discoverability is intentional; then block pointer, keyboard, and form behavior in code and style the state explicitly.
aria-invalid="true"aria-describedbydisabledaria-disabled="true"提交按钮保持启用状态直到请求开始,之后禁用并添加加载动画,但保留原标签。在提交时验证:为失败字段添加,将指向行内错误文本,并聚焦第一个无效字段。当原生控件确实不可用时使用原生属性。仅当需要保留可聚焦性或可发现性时才使用;此时需在代码中阻止指针、键盘和表单行为,并显式样式化该状态。
aria-invalid="true"aria-describedbydisabledaria-disabled="true"8. Accessible Names Everywhere
8. 随处可见的无障碍名称
Icon-only buttons need a descriptive . Visible label text must appear in the accessible name. Decorative elements get , never on a focusable element.
aria-labelaria-hidden="true"仅含图标的按钮需要描述性的。可见标签文本必须包含在无障碍名称中。装饰性元素添加,绝对不要在可聚焦元素上使用该属性。
aria-labelaria-hidden="true"9. Don't Rely on Color Alone
9. 不要仅依赖颜色
Status needs a redundant cue: icon, text, or underline alongside the color. Contrast floors: for text, for UI components and focus indicators (the WCAG 2 minimums; prefers APCA thresholds). When contrast fails, report the failing pair and the threshold it misses; don't change the project's colors unless asked, as the skill covers measuring and, on request, fixing.
4.5:13:1better-colorsbetter-colors状态提示需要冗余线索:除颜色外,还要搭配图标、文本或下划线。对比度标准:文本对比度需达到4.5:1,UI组件和焦点指示器需达到3:1(WCAG 2的最低要求;技能更推荐APCA阈值)。当对比度不达标时,报告不达标颜色对及所需阈值;除非被要求,否则不要修改项目颜色,因为技能负责测量并按需修复。
better-colorsbetter-colors10. Honor prefers-reduced-motion
10. 尊重prefers-reduced-motion
Wrap motion in so it is opt-in. Under reduced motion, replace slides and scales with opacity crossfades; kill parallax and autoplay entirely. Independent of the preference: autoplaying media needs a visible pause control, and toasts carrying actions or errors stay until dismissed.
@media (prefers-reduced-motion: no-preference)将动效包裹在中,让用户主动选择开启动效。在减少动效模式下,将滑动和缩放替换为透明度淡入淡出;完全禁用视差和自动播放。与用户偏好无关的规则:自动播放的媒体需要可见的暂停控件,带有操作或错误信息的提示框需保持显示直到被关闭。
@media (prefers-reduced-motion: no-preference)11. Announce Dynamic Content
11. 播报动态内容
Toasts and inline validation use (); reserve () for errors. The live region must exist empty in the DOM before its content is injected, or it won't announce.
aria-live="polite"role="status"assertiverole="alert"提示框和行内验证使用();仅在错误场景下使用()。实时区域必须在内容注入前就已空状态存在于DOM中,否则无法播报。
aria-live="polite"role="status"assertiverole="alert"12. Alt Text by Purpose
12. 按需设置替代文本
Decorative images get , informative images describe the meaning, functional images describe the action: a search icon button is , not .
alt=""alt="Search"alt="magnifying glass"装饰性图片设置,信息性图片描述其含义,功能性图片描述其操作:搜索图标按钮的替代文本应为,而非。
alt=""alt="Search"alt="放大镜"13. Structure Is Navigation
13. 结构即导航
One per page, no skipped heading levels, exactly one . A "Skip to content" link is the first focusable element, and anchored headings get .
<h1><main>scroll-margin-top每页一个,不要跳过标题层级,且仅有一个。“跳转到内容”链接应为第一个可聚焦元素,锚定标题需添加。
<h1><main>scroll-margin-top14. Survive Zoom and Text Resize
14. 适配缩放与文本调整
The page must work at 200% zoom and reflow at 320px width without horizontal scrolling. Use instead of fixed on text containers, prefer breakpoints where they fit the codebase's conventions, and never use or .
min-heightheightremuser-scalable=nomaximum-scale=1页面必须支持200%缩放,且在320px宽度下可回流而无横向滚动。文本容器使用而非固定,根据代码库约定优先使用作为断点单位,绝对不要使用或。
min-heightheightremuser-scalable=nomaximum-scale=1Common Mistakes
常见错误
| Mistake | Fix |
|---|---|
| Style |
| Hardcoded brand color on focus rings | Keep the default ring ( |
| |
| Placeholder used as the only label | Add a visible |
Positive | Fix the DOM order; only use |
| Live region injected together with its message | Pre-render the empty region, inject text afterwards |
| Use |
| Remove it or make the element non-focusable |
| Functional icon alt describes the picture | Describe the action: |
| 16px input font on mobile (see |
| Submit disabled until the form is valid | Keep it enabled; validate on submit and focus the first error |
| 错误 | 修复方案 |
|---|---|
使用 | 改为样式化 |
| 焦点环硬编码品牌色 | 保留默认焦点环( |
用 | 用 |
| 仅用占位符作为标签 | 添加可见的 |
使用正值 | 修复DOM顺序;仅使用 |
| 实时区域与消息一同注入DOM | 预渲染空的实时区域,之后再注入文本 |
常规提示框使用 | 使用 |
在可聚焦元素上使用 | 移除该属性或让元素不可聚焦 |
| 功能性图标替代文本描述图片内容 | 描述操作: |
使用 | 移动端输入框字体设为16px(详见 |
| 表单验证通过前禁用提交按钮 | 保持提交按钮启用;提交失败时聚焦第一个错误字段 |
Review Output Format
审查输出格式
Present every review in two parts.
所有审查结果分为两部分呈现。
Findings
问题发现
Group findings by principle. Use a markdown table with Severity, Location, Before, After, and Why columns. Include every change made or proposed, not a subset. Never use separate "Before:" / "After:" lines.
- Severity: prevents a task, hides content from assistive technology, or creates a systemic accessibility failure;
HIGHmakes an interaction meaningfully harder;MEDIUMis isolated polish.LOW - Location: cite . If the artifact has no source files, cite the exact screen and component instead.
path/to/file:line - Before / After: show the current implementation and an actionable replacement.
- Why: name the violated principle and its user impact.
Consolidate a repeated systemic issue into one row and list every affected location. Omit principles with no findings.
按原则分组展示问题。使用包含严重程度、位置、修改前、修改后、原因列的Markdown表格。列出所有已做或建议的修改,不要遗漏。不要使用单独的“修改前:”/“修改后:”行。
- 严重程度:表示阻碍任务完成、辅助技术无法识别内容或存在系统性无障碍缺陷;
HIGH表示交互难度显著增加;MEDIUM表示孤立的优化点。LOW - 位置:引用。如果没有源文件,则引用具体屏幕和组件。
path/to/file:line - 修改前/修改后:展示当前实现和可执行的替代方案。
- 原因:指出违反的原则及其对用户的影响。
将重复的系统性问题合并为一行,并列出所有受影响的位置。没有问题的原则可省略。
Example
示例
Accessible names everywhere
随处可见的无障碍名称
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| HIGH | | | Add | The icon-only control has no accessible name |
| HIGH | | | Add | The link destination is unavailable to screen readers |
| 严重程度 | 位置 | 修改前 | 修改后 | 原因 |
|---|---|---|---|---|
| HIGH | | | 添加 | 仅含图标的控件无无障碍名称 |
| HIGH | | | 添加 | 屏幕阅读器无法识别链接目标 |
Visible focus rings
可见焦点环
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| HIGH | | | | Keyboard users cannot see focus |
| HIGH | | | | Menu navigation has no visible focus indicator |
| 严重程度 | 位置 | 修改前 | 修改后 | 原因 |
|---|---|---|---|---|
| HIGH | | | | 键盘用户无法看到焦点 |
| HIGH | | | | 菜单导航无可见焦点指示器 |
Errors that announce
可播报的错误提示
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| HIGH | | Error shown only as | Add | Color alone neither explains nor announces the error |
| MEDIUM | | Submit disabled until the form is valid | Keep submit enabled; on failure, focus the first invalid field | A disabled action hides what must be fixed |
| 严重程度 | 位置 | 修改前 | 修改后 | 原因 |
|---|---|---|---|---|
| HIGH | | 仅用 | 添加 | 仅靠颜色既无法解释也无法播报错误 |
| MEDIUM | | 表单验证通过前禁用提交按钮 | 保持提交按钮启用;提交失败时聚焦第一个错误字段 | 禁用操作会隐藏需要修复的问题 |
Minimum hit area
最小点击区域
| Severity | Location | Before | After | Why |
|---|---|---|---|---|
| MEDIUM | | | Extend the hit area to 44×44px with | The target is too small for reliable touch input |
| 严重程度 | 位置 | 修改前 | 修改后 | 原因 |
|---|---|---|---|---|
| MEDIUM | | | 用 | 目标尺寸过小,无法可靠进行触摸输入 |
Verification and Verdict
验证与结论
After the findings:
- Verification: list the exact checks run and their observed results, including keyboard traversal, accessible-name inspection, and screen-reader or automated checks when applicable. If a check was not run, state what still needs verification.
- Verdict: if any
Blockfinding remains,HIGHif onlyNeeds changesorMEDIUMfindings remain, andLOWonly when no actionable findings remain.Approve
When there are no findings, omit the tables, state "No actionable accessibility findings", report verification, and end with .
Approve问题发现之后:
- 验证:列出执行的具体检查及其结果,包括键盘遍历、无障碍名称检查、屏幕阅读器或自动化检查(如适用)。如果未执行某项检查,说明仍需验证的内容。
- 结论:若存在未解决的级问题,标记为
HIGH;若仅存在Block或MEDIUM级问题,标记为LOW;仅当无待解决问题时,标记为Needs changes。Approve
如果没有问题,省略表格,说明“无待解决的无障碍问题”,报告验证情况,最后标记为。
Approve