可访问性基础 accessibility-fundamentals

这个技能提供了可访问性基础知识,涵盖WCAG标准、ARIA属性、键盘导航等关键方面,适用于前端开发中构建表单、按钮、模态框等交互元素时确保对所有用户可访问。关键词:可访问性、WCAG、ARIA、键盘导航、屏幕阅读器、前端开发。

前端开发 0 次安装 0 次浏览 更新于 3/8/2026

name: accessibility-fundamentals description: 回顾可访问性,包括 WCAG、ARIA、键盘导航。当新手构建表单、按钮、模态框、交互元素,或询问“这可以访问吗”、“a11y”、“屏幕阅读器”时使用。

可访问性基础回顾

“可访问性不是一项功能,而是一个要求。如果 15% 的用户无法使用你的应用,你就失败了 15% 的用户。”

何时应用

激活此技能时:

  • 审查包含按钮、链接或表单的 JSX
  • 查看自定义交互组件
  • 带有输入和标签的表单
  • 导航菜单
  • 模态对话框
  • 任何用户交互代码

可访问性清单

必须有(每个交互元素)

  • [ ] 键盘可访问 — 所有操作都可通过 Tab + Enter/Space 使用
  • [ ] 焦点可见 — 聚焦元素的清晰视觉指示器
  • [ ] 语义元素 — 使用 <button> 而非 <div onClick>
  • [ ] 表单标签 — 每个输入都有关联的 <label>
  • [ ] 替代文本 — 图像具有描述性的 alt 属性
  • [ ] 足够对比度 — 文本在背景上可读(4.5:1 比率)

应该有(复杂交互)

  • [ ] ARIA 标签 — 纯图标按钮有 aria-label
  • [ ] 焦点陷阱 — 模态框在关闭前捕获焦点
  • [ ] 跳过链接 — 为键盘用户提供“跳转到主要内容”
  • [ ] 活动区域 — 动态内容向屏幕阅读器宣布
  • [ ] 错误消息 — 使用 aria-describedby 链接到输入

切勿做

  • [ ] 仅依赖颜色 — 颜色不应是唯一指示器
  • [ ] 移除焦点轮廓 — 永远不要使用 outline: none 而无替代
  • [ ] 使用 div 作为按钮 — 使用语义 <button><a>
  • [ ] 困住用户 — 始终提供从模态框/菜单中退出的方式

常见错误(反模式)

1. Div 作为按钮

// ❌ 错误:不可键盘访问,无语义
<div onClick={handleClick} className="button">
  点击我
</div>

// ✅ 良好:原生按钮元素
<button onClick={handleClick} className="button">
  点击我
</button>

为何重要: <div onClick> 不接收键盘焦点,不响应 Enter/Space,屏幕阅读器不会宣布为按钮。

2. 缺少表单标签

// ❌ 错误:输入无标签
<input type="email" placeholder="Email" />

// ✅ 良好:标签链接到输入
<label htmlFor="email">Email</label>
<input id="email" type="email" placeholder="example@email.com" />

// ✅ 同样良好:包裹标签
<label>
  Email
  <input type="email" />
</label>

3. 纯图标按钮

// ❌ 错误:无可访问名称
<button onClick={handleDelete}>
  <TrashIcon />
</button>

// ✅ 良好:屏幕阅读器的 ARIA 标签
<button onClick={handleDelete} aria-label="删除项目">
  <TrashIcon aria-hidden="true" />
</button>

4. 移除焦点样式

/* ❌ 错误:焦点不可见 */
button:focus {
  outline: none;
}

/* ✅ 良好:自定义但可见的焦点 */
button:focus {
  outline: none;
  box-shadow: 0 0 0 3px rgba(66, 153, 225, 0.6);
}

/* ✅ 最佳:使用 focus-visible */
button:focus-visible {
  outline: 2px solid #4299e1;
  outline-offset: 2px;
}

5. 非描述性链接文本

// ❌ 错误:“点击此处”未告知屏幕阅读器任何信息
<p>
  阅读我们的隐私政策,<a href="/privacy">点击此处</a>。
</p>

// ✅ 良好:链接文本描述目的地
<p>
  阅读我们的 <a href="/privacy">隐私政策</a>。
</p>

6. 缺少标题层级

// ❌ 错误:屏幕阅读器无法导航
<div className="title">欢迎</div>
<div className="subtitle">入门指南</div>

// ✅ 良好:正确的标题
<h1>欢迎</h1>
<h2>入门指南</h2>

苏格拉底式提问

用这些提问代替直接给出答案:

  1. 键盘:“你能仅使用键盘完成此操作吗?”
  2. 焦点:“如果我通过 Tab 键浏览页面,我能看到我在哪里吗?”
  3. 语义:“屏幕阅读器为这个元素宣布什么?”
  4. 标签:“如果占位符消失,用户如何知道要输入什么?”
  5. 颜色:“如果有人是色盲,他们还能理解这个 UI 吗?”
  6. 替代文本:“如果图像未加载,会丢失什么上下文?”

测试可访问性

手动测试

  1. 键盘测试:仅使用 Tab 键导航整个页面
  2. 焦点测试:你总能看见焦点在哪里吗?
  3. 缩放测试:布局在 200% 缩放时会破坏吗?
  4. 屏幕阅读器:尝试 VoiceOver(Mac)或 NVDA(Windows)

自动化测试

# 在你的测试文件中
# 模式:用于 React Testing Library 的 axe-core
import { axe } from 'jest-axe';

it('应该没有可访问性违规', async () => {
  const { container } = render(<YourComponent />);
  const results = await axe(container);
  expect(results).toHaveNoViolations();
});

ARIA 参考

常见 ARIA 属性

属性 使用场景
aria-label 为纯图标按钮提供名称
aria-labelledby 指向具有可见标签的元素
aria-describedby 指向描述(错误消息)
aria-hidden="true" 向屏幕阅读器隐藏装饰性图标
aria-expanded 指示下拉菜单/手风琴状态
aria-live 宣布动态内容变化
role 定义元素的用途(谨慎使用)

ARIA 的第一条规则

“没有 ARIA 比糟糕的 ARIA 更好。”

首先使用语义 HTML。仅当 HTML 无法表达你需要的内容时使用 ARIA。


特定框架指南

React

// 模式:带有可访问名称的按钮
<button
  onClick={handleAction}
  aria-label="关闭模态框"
>
  <XIcon aria-hidden="true" />
</button>

表单错误模式

// 模式:错误链接到输入
<label htmlFor="email">Email</label>
<input
  id="email"
  type="email"
  aria-describedby={error ? "email-error" : undefined}
  aria-invalid={error ? "true" : undefined}
/>
{error && (
  <span id="email-error" role="alert">
    {error}
  </span>
)}

需要指出的危险信号

信号 提问
<div onClick> “键盘用户尝试点击这个时会发生什么?”
outline: none “键盘用户如何知道他们在哪里?”
无表单标签 “屏幕阅读器如何知道这个输入是做什么的?”
纯图标按钮 “屏幕阅读器为这个按钮宣布什么?”
颜色作为唯一指示器 “如果有人是红绿色盲怎么办?”
tabIndex > 0 “这破坏了自然的 Tab 顺序。为什么需要它?”

面试联系

“我实施了可访问性最佳实践,包括语义 HTML、正确的表单标签和键盘导航,确保我们的应用对所有用户可用。”

STAR 故事素材:

  • “识别了我们表单中的可访问性问题并修复了它们…”
  • “在我们的模态组件中实施了正确的焦点管理…”
  • “为我们的通知系统添加了屏幕阅读器支持…”

MCP 使用

Context7 - 框架文档

获取:WAI-ARIA 实践
获取:React 可访问性文档

Octocode - 真实示例

搜索:“aria-label” + “按钮” 模式
搜索:模态焦点陷阱实现

资源

  • WCAG 2.1 指南(检查 Context7)
  • Deque 的 axe-core 用于自动化测试
  • WebAIM 颜色对比检查器