无障碍设计(WCAG 2.1 AA)

作者:鹿Sir开发工具v1

WCAG 2.1 AA 合规模式、屏幕阅读器兼容、键盘导航与 ARIA 最佳实践指南。覆盖语义化 HTML、焦点管理、颜色对比度与辅助技术测试。当用户需要实现可访问界面、审查 UI 组件无障碍性、开展 WCAG 合规审计、设计键盘导航或为自定义组件编写 ARIA 时触发。触发词:无障碍、可访问性、WCAG、ARIA、屏幕阅读器、键盘导航、对比度、a11y。

下载量
356
点赞
87
价格
免费

技能文档

---
name: diegosouzapw-accessibility-design
title: 无障碍设计(WCAG 2.1 AA)
category: 开发工具
description: "WCAG 2.1 AA 合规模式、屏幕阅读器兼容、键盘导航与 ARIA 最佳实践指南。覆盖语义化 HTML、焦点管理、颜色对比度与辅助技术测试。当用户需要实现可访问界面、审查 UI 组件无障碍性、开展 WCAG 合规审计、设计键盘导航或为自定义组件编写 ARIA 时触发。触发词:无障碍、可访问性、WCAG、ARIA、屏幕阅读器、键盘导航、对比度、a11y。"
---

# 无障碍设计(Accessibility Design)

以无障碍专家的角色,为数字产品提供 WCAG 2.1 AA 合规的全面实施指导,建立语义化标记、辅助技术兼容与包容性交互设计的模式。

## 技能工作流

### 步骤1:确认适用场景与硬性约束

适用场景:实现可访问用户界面、审查 UI 组件无障碍合规性、审计 WCAG 2.1 AA 合规、设计键盘导航模式、为自定义组件实现 ARIA、使用屏幕阅读器与辅助技术测试、确保颜色对比度与视觉无障碍。

六条硬性约束(任何场景不可违反):

1. **语义化 HTML 优先** — ARIA 只用于增强,绝不能替代正确的标记
2. 优先使用原生 HTML 元素
3. 绝不完全移除焦点指示器
4. 绝不仅靠颜色传达信息
5. 所有功能必须可通过键盘访问
6. 保持逻辑的标题层级顺序,不跳级

### 步骤2:按 POUR 四原则评估

所有无障碍工作遵循 POUR 四原则:

- **可感知(Perceivable)**:为非文本内容提供文本替代;内容可适配不同呈现方式;内容可辨别(颜色、对比度、音频控制)
- **可操作(Operable)**:所有功能键盘可访问;提供足够时间阅读和使用内容;避免引发癫痫或身体反应的内容;帮助用户导航、查找内容并确定位置
- **可理解(Understandable)**:文本可读可理解;页面呈现与操作可预测;帮助用户避免和纠正错误
- **健壮(Robust)**:最大化兼容当前与未来的辅助技术;使用有效、语义化的标记;确保所有功能可被程序化访问

### 步骤3:语义化 HTML 与渐进增强

正确示范:

```html
<button type="submit">Submit Form</button>
```

错误示范:

```html
<div role="button" tabindex="0" onclick="submit()">Submit Form</div>
```

原生元素选用:

- `<button>` 用于动作,`<a href>` 用于导航
- `<input>`、`<select>`、`<textarea>` 用于表单控件
- `<nav>`、`<main>`、`<aside>`、`<header>`、`<footer>` 作为地标区域
- `<h1>` 到 `<h6>` 构成标题层级

文档结构与跳转链接:

```html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Descriptive Page Title - Site Name</title>
</head>
<body>
  <a href="#main-content" class="skip-link">Skip to main content</a>

  <header role="banner">
    <nav aria-label="Main navigation">
      <!-- Navigation content -->
    </nav>
  </header>

  <main id="main-content" role="main">
    <h1>Page Heading</h1>
    <!-- Page content -->
  </main>

  <footer role="contentinfo">
    <!-- Footer content -->
  </footer>
</body>
</html>
```

跳转链接样式:

```css
.skip-link {
  position: absolute;
  top: -40px;
  left: 0;
  padding: 8px 16px;
  background: #000;
  color: #fff;
  z-index: 100;
}

.skip-link:focus {
  top: 0;
}
```

渐进增强四层:语义化 HTML 提供无障碍基线 → CSS 增强呈现而不破坏结构 → JavaScript 增加交互同时保持键盘访问 → ARIA 补足 HTML 未覆盖的复杂组件。

### 步骤4:焦点管理与键盘导航

可见焦点指示器:

```css
:focus {
  outline: 2px solid #005fcc;
  outline-offset: 2px;
}

/* Enhanced focus for better visibility */
:focus-visible {
  outline: 3px solid #005fcc;
  outline-offset: 3px;
  box-shadow: 0 0 0 6px rgba(0, 95, 204, 0.25);
}

/* Never remove focus indicators entirely */
:focus:not(:focus-visible) {
  outline: 2px solid transparent;
  box-shadow: 0 0 0 2px #005fcc;
}
```

模态框焦点圈定:

```javascript
function trapFocus(element) {
  const focusableElements = element.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const firstFocusable = focusableElements[0];
  const lastFocusable = focusableElements[focusableElements.length - 1];

  element.addEventListener('keydown', (e) => {
    if (e.key !== 'Tab') return;

    if (e.shiftKey) {
      if (document.activeElement === firstFocusable) {
        lastFocusable.focus();
        e.preventDefault();
      }
    } else {
      if (document.activeElement === lastFocusable) {
        firstFocusable.focus();
        e.preventDefault();
      }
    }
  });
}
```

标准键盘操作约定:

| 按键 | 动作 |
|------|------|
| Tab | 焦点移到下一个可聚焦元素 |
| Shift+Tab | 焦点移到上一个可聚焦元素 |
| Enter/Space | 激活按钮和链接 |
| 方向键 | 在组件内导航(菜单、选项卡、单选组) |
| Escape | 关闭模态框、菜单、下拉框 |
| Home/End | 移到列表第一项/最后一项 |

Tab 顺序规则:Tab 顺序必须与视觉顺序一致;**禁止使用正数 `tabindex`**;`tabindex="0"` 让非交互元素可聚焦;`tabindex="-1"` 让元素可被程序聚焦但不进 Tab 序列。

```html
<!-- Correct: Tab order matches visual order -->
<form>
  <label for="name">Name</label>
  <input id="name" type="text">

  <label for="email">Email</label>
  <input id="email" type="email">

  <button type="submit">Submit</button>
</form>
```

### 步骤5:ARIA 模式

ARIA 使用时机:自定义组件(Tabs、手风琴、轮播、树形视图);动态内容(实时区域播报更新);关系连接(标签关联复杂控件);状态表达(展开/折叠、选中、按下)。

选项卡模式:

```html
<!-- Tab pattern -->
<div role="tablist" aria-label="Settings tabs">
  <button role="tab" aria-selected="true" aria-controls="panel1" id="tab1">
    General
  </button>
  <button role="tab" aria-selected="false" aria-controls="panel2" id="tab2">
    Security
  </button>
</div>
<div role="tabpanel" id="panel1" aria-labelledby="tab1">
  <!-- Panel content -->
</div>
<div role="tabpanel" id="panel2" aria-labelledby="tab2" hidden>
  <!-- Panel content -->
</div>
```

常用 ARIA 状态与属性:

| 属性 | 用途 | 示例 |
|------|------|------|
| `aria-expanded` | 表示可展开元素状态 | `aria-expanded="false"` |
| `aria-selected` | 表示选中状态 | `aria-selected="true"` |
| `aria-pressed` | 表示切换按钮状态 | `aria-pressed="mixed"` |
| `aria-hidden` | 对辅助技术隐藏内容 | `aria-hidden="true"` |
| `aria-live` | 播报动态内容 | `aria-live="polite"` |
| `aria-describedby` | 引用描述性内容 | `aria-describedby="hint"` |
| `aria-labelledby` | 引用标注性内容 | `aria-labelledby="heading"` |

实时区域:

```html
<!-- Polite: Announces when user is idle -->
<div aria-live="polite" aria-atomic="true">
  Form saved successfully
</div>

<!-- Assertive: Interrupts immediately (use sparingly) -->
<div aria-live="assertive" role="alert">
  Error: Please correct the highlighted fields
</div>

<!-- Status messages -->
<div role="status">
  Loading... 50% complete
</div>
```

### 步骤6:表单无障碍

标签与说明:

```html
<!-- Explicit label association -->
<label for="username">Username</label>
<input type="text" id="username" name="username"
       aria-describedby="username-hint">
<span id="username-hint">Must be 3-20 characters</span>

<!-- Grouped controls with fieldset -->
<fieldset>
  <legend>Shipping Address</legend>
  <label for="street">Street</label>
  <input type="text" id="street">
  <!-- More fields -->
</fieldset>
```

错误处理:

```html
<label for="email">Email</label>
<input type="email" id="email"
       aria-invalid="true"
       aria-describedby="email-error">
<span id="email-error" role="alert">
  Please enter a valid email address (example: user@domain.com)
</span>
```

错误处理要求:指出出错字段;说明错误原因;提供纠正指引;字段上加 `aria-invalid`;通过实时区域或 `role="alert"` 播报错误。

必填字段:

```html
<label for="name">
  Name <span aria-hidden="true">*</span>
  <span class="sr-only">(required)</span>
</label>
<input type="text" id="name" required aria-required="true">
```

### 步骤7:图片、媒体与颜色对比

替代文本:

```html
<!-- Informative image -->
<img src="chart.png" alt="Q3 revenue increased 15% compared to Q2">

<!-- Decorative image -->
<img src="divider.png" alt="" role="presentation">

<!-- Complex image with extended description -->
<figure>
  <img src="flowchart.png" alt="User registration process"
       aria-describedby="flowchart-desc">
  <figcaption id="flowchart-desc">
    The registration process begins with email verification,
    followed by profile creation, and ends with account activation.
  </figcaption>
</figure>
```

视频与音频:

```html
<video controls>
  <source src="video.mp4" type="video/mp4">
  <track kind="captions" src="captions.vtt" srclang="en" label="English">
  <track kind="descriptions" src="descriptions.vtt" srclang="en"
         label="Audio descriptions">
</video>
```

最低对比度要求:

| 内容类型 | AA 最低比率 | AAA 增强比率 |
|----------|------------|--------------|
| 普通文本(< 18pt) | 4.5:1 | 7:1 |
| 大号文本(>= 18pt 或 14pt 加粗) | 3:1 | 4.5:1 |
| UI 组件与图形 | 3:1 | 不适用 |

绝不仅靠颜色传达信息:

```html
<!-- Bad: Color only indicates error -->
<input style="border-color: red">

<!-- Good: Color plus icon and text -->
<input aria-invalid="true" aria-describedby="error">
<span id="error">
  <svg aria-hidden="true"><!-- Error icon --></svg>
  Invalid email format
</span>
```

### 步骤8:动效与动画

尊重用户偏好:

```css
/* Reduce motion for users who prefer it */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}
```

自动播放内容:避免自动播放视频或音频;提供暂停、停止或隐藏动态内容的控件;动画限制在 5 秒内或提供停止机制。

### 步骤9:测试方法论

**自动化测试**(约能发现 30-40% 的问题):axe DevTools(浏览器扩展页面分析)、WAVE(网页无障碍评估)、Lighthouse(Chrome DevTools 无障碍审计)、pa11y(命令行测试)。

**键盘测试**:断开或禁用鼠标;用 Tab/Shift+Tab 导航整个页面;验证所有交互元素可达;验证焦点指示器可见;测试所有快捷键;确认所有模态框和菜单可 Escape 退出。

**屏幕阅读器测试**:

| 平台 | 屏幕阅读器 | 浏览器 |
|------|-----------|--------|
| Windows | NVDA(免费) | Firefox, Chrome |
| Windows | JAWS | Chrome, Edge |
| macOS | VoiceOver | Safari |
| iOS | VoiceOver | Safari |
| Android | TalkBack | Chrome |

检查清单:所有图片有适当 alt 文本;标题体现页面结构;链接和按钮有描述性名称;表单字段有标签;错误消息被播报;动态内容更新被播报;表格有正确表头;自定义组件播报状态变化。

**视觉测试**:缩放 200% 验证无横向滚动;开启高对比度模式测试;禁用图片验证内容仍可理解;增大浏览器字号测试。

### 步骤10:常见组件模式

模态框:

```html
<div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
  <h2 id="dialog-title">Confirm Action</h2>
  <p>Are you sure you want to proceed?</p>
  <button type="button">Cancel</button>
  <button type="button">Confirm</button>
</div>
```

要求:打开时焦点移入对话框;焦点被圈定在对话框内;Escape 键可关闭;关闭时焦点返回触发元素。

手风琴:

```html
<div class="accordion">
  <h3>
    <button aria-expanded="true" aria-controls="section1">
      Section 1
    </button>
  </h3>
  <div id="section1" role="region" aria-labelledby="section1-heading">
    <!-- Content -->
  </div>
</div>
```

导航菜单:

```html
<nav aria-label="Main">
  <ul>
    <li><a href="/" aria-current="page">Home</a></li>
    <li>
      <button aria-expanded="false" aria-haspopup="true">
        Products
      </button>
      <ul>
        <li><a href="/products/a">Product A</a></li>
        <li><a href="/products/b">Product B</a></li>
      </ul>
    </li>
  </ul>
</nav>
```

数据表格:

```html
<table>
  <caption>Q3 Sales by Region</caption>
  <thead>
    <tr>
      <th scope="col">Region</th>
      <th scope="col">Units Sold</th>
      <th scope="col">Revenue</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">North</th>
      <td>1,234</td>
      <td>$45,678</td>
    </tr>
  </tbody>
</table>
```

## 参考资料

- [WCAG 2.1 快速参考](https://www.w3.org/WAI/WCAG21/quickref/)
- [WAI-ARIA 创作实践](https://www.w3.org/WAI/ARIA/apg/)
- [Inclusive Components](https://inclusive-components.design/)
- [A11y Project 清单](https://www.a11yproject.com/checklist/)

使用说明

# 无障碍设计(WCAG 2.1 AA)

WCAG 2.1 AA 合规实施指南:语义化 HTML、焦点管理、键盘导航、ARIA 模式与辅助技术测试,覆盖实现、审查与审计全场景。

## 使用

```text
帮我审查这个页面的无障碍合规性,按 WCAG 2.1 AA 标准列出问题。
```

```text
给这个自定义下拉组件加上正确的 ARIA 属性和键盘导航。
```

```text
我们的表单错误提示只用了红色边框,怎么改得更无障碍?
```

## 工作原理

- **POUR 四原则评估**:可感知、可操作、可理解、健壮,作为所有无障碍决策的框架
- **语义化 HTML 优先**:ARIA 只做增强不做替代,六条硬性约束不可违反
- **十大实施步骤**:从场景约束、POUR 评估到焦点管理、ARIA 模式、表单、对比度、动效、测试与组件模式
- **三层测试法**:自动化工具(axe/WAVE/Lighthouse)+ 键盘走查 + 屏幕阅读器实测

## 目录说明

- `SKILL.md` — 十步工作流与代码模式库

如何安装此技能?

访问技能市场,点击「安装」按钮,按提示将技能包放入 AI 编程助手的 skills 目录即可。

浏览技能市场

支持平台:Qoder · QoderWork · Claude · Codex 等 AI 编程助手