关于 accessibility
面向设计师和开发者的无障碍指南,依据 WCAG 2.2 与 Lighthouse 审计涵盖设计原则、实现模式和测试清单。
主要功能
- 01WCAG 2.2 原则与合规等级
- 02键盘操作与焦点管理
- 03颜色对比和文本替代
- 04表单、错误与 ARIA 模式
- 05自动化及手动测试清单
适用场景
- 01检查页面是否符合无障碍要求
- 02实现键盘可操作的界面
- 03审查表单和错误提示
- 04规划发布前的无障碍测试
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ thedesignproject/ agent-skills --skill accessibility安装后在 Claude Code 中输入/accessibility确认已加载。
附带文件references/A11Y-PATTERNS.mdreferences/WCAG.md
详细介绍
无障碍访问(a11y)
基于 WCAG 2.2 和 Lighthouse 无障碍审查的综合无障碍指南。目标是让所有人都能使用内容,包括残障人士。
WCAG 原则:POUR
| 原则 | 描述 |
|---|---|
| Perceivable(可感知) | 内容可通过不同感官感知 |
| Operable(可操作) | 所有用户都能操作界面 |
| Understandable(可理解) | 内容和界面易于理解 |
| Robust(健壮) | 内容可与辅助技术配合使用 |
合规等级
| 等级 | 要求 | 目标 |
|---|---|---|
| A | 最低无障碍要求 | 必须通过 |
| AA | 标准合规 | 应通过(许多司法辖区的法律要求) |
| AAA | 增强无障碍访问 | 最好达到 |
可感知
文本替代内容(1.1)
图片需要替代文本:
<img src="chart.png">
<img src="chart.png" alt="Bar chart showing 40% increase in Q3 sales">
<img src="decorative-border.png" alt="" role="presentation">
<figure>
<img src="infographic.png" alt="2024 market trends infographic"
aria-describedby="infographic-desc">
<figcaption id="infographic-desc">
</figcaption>
</figure>
图标按钮需要无障碍名称:
<button><svg></svg></button>
<button aria-label="Open menu">
<svg aria-hidden="true"></svg>
</button>
<button>
<svg aria-hidden="true"></svg>
<span class="visually-hidden">Open menu</span>
</button>
视觉隐藏类:
.visually-hidden {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
颜色对比度(1.4.3、1.4.6)
| 文本大小 | AA 最低要求 | AAA 增强要求 |
|---|---|---|
| 普通文本(< 18px / < 14px 粗体) | 4.5:1 | 7:1 |
| 大号文本(≥ 18px / ≥ 14px 粗体) | 3:1 | 4.5:1 |
| UI 组件和图形 | 3:1 | 3:1 |
/* ❌ Low contrast (2.5:1) */
.low-contrast {
color: #999;
background: #fff;
}
/* ✅ Sufficient contrast (7:1) */
.high-contrast {
color: #333;
background: #fff;
}
/* ✅ Focus states need contrast too (3:1 against background, WCAG 1.4.11) */
:focus-visible {
outline: 2px solid currentColor;
outline-offset: 2px;
}
不要只依赖颜色传达信息:
<input class="error-border">
<style>.error-border { border-color: red; }</style>
<div class="field-error">
<input aria-invalid="true" aria-describedby="email-error">
<span id="email-error" class="error-message">
<svg aria-hidden="true"></svg>
Please enter a valid email address
</span>
</div>
媒体替代内容(1.2)
<video controls>
<source src="video.mp4" type="video/mp4">
<track kind="captions" src="captions.vtt" srclang="en" label="English" default>
<track kind="descriptions" src="descriptions.vtt" srclang="en" label="Descriptions">
</video>
<audio controls>
<source src="podcast.mp3" type="audio/mp3">
</audio>
<details>
<summary>Transcript</summary>
<p>Full transcript text...</p>
</details>
可操作
键盘可访问性(2.1)
所有功能都必须支持键盘操作。 优先使用原生交互元素——<button>、<a href> 和表单控件会自动处理 Enter/Space 键激活、焦点和辅助技术语义。只有无法使用原生元素时,才手动添加键盘处理逻辑。
<div class="card" onclick="handleAction()">Open</div>
<button type="button" onclick="handleAction()">Open</button>
// ✅ When you MUST use a non-interactive element (e.g. div with role="button"),
// make it focusable AND handle keyboard activation. Do NOT add this to a native
// <button> — Enter/Space already fire click, so you'd double-trigger.
element.setAttribute('role', 'button');
element.setAttribute('tabindex', '0');
element.addEventListener('click', handleAction);
element.addEventListener('keydown', (e) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
handleAction();
}
});
不得设置键盘陷阱。 用户必须能够使用 Tab 键进入和离开每个组件。对话框请使用模态框焦点陷阱模式——原生 <dialog> 元素会自动处理这一点。
焦点可见(2.4.7)
/* ❌ Never remove focus outlines */
*:focus { outline: none; }
/* ✅ Use :focus-visible for keyboard-only focus */
:focus {
outline: none;
}
:focus-visible {
outline: 2px solid currentColor; /* inherits text color → already contrast-checked */
outline-offset: 2px;
}
/* ✅ Or pick a brand color and verify ≥3:1 contrast against every background it lands on */
button:focus-visible {
box-shadow: 0 0 0 3px rgba(0, 95, 204, 0.5);
}
焦点不被遮挡(2.4.11)——2.2 新增
当元素获得键盘焦点时,不得被粘性页眉、页脚或重叠面板等其他由作者创建的内容完全遮挡。在 AAA 等级(2.4.12)下,焦点元素的任何部分都不得被遮挡。
/* ✅ Account for sticky headers when scrolling to focused elements */
:target {
scroll-margin-top: 80px;
}
/* ✅ Ensure focused items clear fixed/sticky bars */
:focus {
scroll-margin-top: 80px;
scroll-margin-bottom: 60px;
}
跳过链接(2.4.1)
提供跳过链接,让键盘用户可以跳过重复的导航内容。完整标记和样式请参见跳过链接模式。
目标尺寸(2.5.8)——2.2 新增
交互目标的尺寸必须至少为 24 × 24 CSS 像素(AA)。例外情况:行内文本链接、尺寸由浏览器控制的元素,以及在边界框中心绘制直径为 24px 的圆后不会与其他目标重叠的目标。
/* ✅ Minimum target size */
button,
[role="button"],
input[type="checkbox"] + label,
input[type="radio"] + label {
min-width: 24px;
min-height: 24px;
}
/* ✅ Comfortable target size (recommended 44×44) */
.touch-target {
min-width: 44px;
min-height: 44px;
display: inline-flex;
align-items: center;
justify-content: center;
}
拖动操作(2.5.7)——2.2 新增
任何需要拖动的操作都必须提供单指针替代方式(例如按钮、输入框)。可排序列表示例请参见拖动操作模式。
时间限制(2.2)
// Allow users to extend time limits
function showSessionWarning() {
const modal = createModal({
title: 'Session Expiring',
content: 'Your session will expire in 2 minutes.',
actions: [
{ label: 'Extend session', action: extendSession },
{ label: 'Log out', action: logout }
],
timeout: 120000
});
}
动效(2.3)
/* Respect reduced motion preference */
@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;
}
}
可理解
页面语言(3.1.1)
<html>
<html lang="en">
<p>The French word for hello is <span lang="fr">bonjour</span>.</p>
导航一致性(3.2.3)
<nav aria-label="Main">
<ul>
<li><a href="/" aria-current="page">Home</a></li>
<li><a href="/products">Products</a></li>
<li><a href="/about">About</a></li>
</ul>
</nav>
帮助一致性(3.2.6)——2.2 新增
如果某种帮助方式(联系信息、聊天工具、常见问题链接、自助选项)在多个页面中重复出现,则每次都必须按相同的相对顺序显示。依赖固定位置的用户不应每次都在页面上寻找帮助。
表单标签(3.3.2)
每个输入框都需要以编程方式关联的标签。有关显式、隐式和说明性示例,请参见表单标签模式。
错误处理(3.3.1、3.3.3)
使用 role="alert" 或 aria-live 向屏幕阅读器播报错误,在无效字段上设置 aria-invalid="true",并在提交时将焦点移至第一个错误处。完整标记和 JS 请参见错误处理模式。
冗余输入(3.3.7)— 2.2 版新增
不要强迫用户在同一会话中重复输入已提供的信息。自动填入之前步骤中的信息,或让用户从之前输入过的值中选择。例外情况:安全性重新确认以及已过期的内容。
<fieldset>
<legend>Shipping address</legend>
<label>
<input type="checkbox" id="same-as-billing" checked>
Same as billing address
</label>
</fieldset>
易于使用的身份验证(3.3.8)— 2.2 版新增
登录流程不得依赖认知功能测试(例如记住密码、解谜),除非至少满足以下一项:
- 提供复制粘贴或自动填充机制
- 提供其他方式(例如通行密钥、SSO、电子邮件链接)
- 测试使用物体识别或个人内容(仅适用于 AA;AAA 不包含此例外)
<input type="password" id="password" autocomplete="current-password">
<button type="button">Sign in with passkey</button>
<button type="button">Email me a login link</button>
稳健性
ARIA 用法(4.1.2)
优先使用原生元素:
<div role="button" tabindex="0">Click me</div>
<button>Click me</button>
<div role="checkbox" aria-checked="false">Option</div>
<label><input type="checkbox"> Option</label>
**需要使用 ARIA 时,**请使用正确的角色和状态。完整的标签列表示例请参阅 ARIA 标签页模式。
实时区域(4.1.3)
使用 aria-live 区域播报动态内容变化,而不移动焦点。有关标记和 showNotification() 助手函数,请参阅实时区域模式。
测试清单
自动化测试
# Lighthouse accessibility audit
npx lighthouse https://example.com --only-categories=accessibility
# axe-core
npm install @axe-core/cli -g
axe https://example.com
手动测试
- 键盘导航: 使用 Tab 遍历整个页面,并使用 Enter/Space 激活
- 屏幕阅读器: 使用 VoiceOver(Mac)、NVDA(Windows)或 TalkBack(Android)进行测试
- 缩放: 内容在 200% 缩放下仍可使用
- 高对比度: 使用 Windows 高对比度模式进行测试
- 减少动态效果: 使用
prefers-reduced-motion: reduce进行测试 - 焦点顺序: 顺序合理,并符合视觉顺序
- 目标尺寸: 交互元素至少达到 24×24px
VoiceOver 和 NVDA 快捷键请参阅屏幕阅读器命令参考。
按影响程度分类的常见问题
严重(立即修复)
- 表单缺少标签
- 图片缺少替代文本
- 颜色对比度不足
- 键盘陷阱
- 缺少焦点指示器
较严重(上线前修复)
- 缺少页面语言声明
- 缺少标题结构
- 链接文本描述不清
- 媒体自动播放
- 缺少跳过链接
中等(尽快修复)
- 图标缺少 ARIA 标签
- 导航不一致
- 未能识别错误
- 计时功能缺少控件
- 缺少地标区域