SuperAPI AI Directory

verify-frontend-accessibility

Frontend & websites

View repository

Updated 10-16 09:30

About this skill

Accessibility — accessibility assurance

Entry/Exit

  • Entry: Build UI components, forms, navigation, or interactive elements
  • Exit: Components that pass a11y checks
  • Points to: After a11y verification passes, continue build or enter /review
  • Preload: CANON.md + build-frontend-ui-engineering/SKILL.md
  • Output path: Components that pass a11y checks → verify-workflow-review(enter review) or continue build

When not to use

  • The change does not involve user-interactive UI, forms, navigation, or visual presentation
  • It is only pure copy, backend, scripts, or data migration
  • The UI must be implemented first, and there is currently no inspectable interface

Iron Law

Goal: WCAG 2.1 AA

AA is the minimum commercial standard to meet. AAA is strived for in specific areas but is not a global requirement.

Three pillars

1. Keyboard navigation

每个交互元素必须通过键盘可达和可操作:
├── Tab → 进入元素
├── Shift+Tab → 离开元素(回到上一个)
├── Enter / Space → 激活按钮/链接
├── Escape → 关闭模态框/下拉
├── Arrow Keys → 在选项间移动(菜单、tabs、单选组)
└── 焦点顺序 → 逻辑顺序(DOM 顺序匹配视觉顺序)
// Bad: div 不可通过键盘操作
<div onClick={handleClick}>删除</div>

// Good: button 自动有键盘支持
<button onClick={handleClick}>删除</button>

Focus trap: Modal opens → focus is trapped inside the modal (Tab cycle does not escape). Modal closes → focus returns to the trigger element.

2. Screen readers

// 图像: 始终有 alt
<img src="logo.png" alt="Company Name" />
// 装饰性图像: alt="" (空,不是缺失)

// 图标按钮: aria-label
<button aria-label="关闭对话框">
  <XIcon />
</button>

// 表单: label 和 input 关联
<label htmlFor="task-title">任务标题</label>
<input id="task-title" type="text" />

// 错误关联
<input id="email" aria-describedby="email-error" />
<span id="email-error" role="alert">请输入有效的邮箱地址</span>

ARIA rule: Native HTML elements (<button>、<input>、<a>) already have implicit ARIA. No need to add role="button" to <button>. ARIA is only needed when native elements are not used.

3. Visual

对比度 (WCAG AA):
├── 普通文本: ≥ 4.5:1
├── 大文本 (≥18px bold 或 ≥24px): ≥ 3:1
└── UI 组件/图形: ≥ 3:1

颜色不是唯一的信息传达方式:
├── 错误状态: 红色边框 + 图标 + 文字
├── 成功状态: 绿色边框 + 图标 + 文字
├── 链接: 下划线(不仅仅是颜色)
└── 图表: 图案/纹理 + 颜色

Key checks

Forms

  • Every input has a label
  • Required fields have an indicator (asterisk + "required" text, not color alone)
  • Error messages are associated with the corresponding input (aria-describedby)
  • On validation error before submission, focus jumps to the first error field

Images

  • Content images have descriptive alt
  • Decorative images have alt=""
  • SVG icons have aria-label or are hidden with aria-hidden="true" hidden

Navigation

  • The page has a skip-to-content link
  • The current page/location has aria-current="page"
  • Main navigation has <nav> landmark

Page structure

  • Has a semantic heading hierarchy (h1 → h2 → h3, no skipped levels)
  • Has <main>、<header>、<footer> landmarks
  • Information does not rely on purely visual presentation ("right panel", "green button")

Dynamic content

  • Toast/notifications have role="alert" or aria-live
  • Loading states are announced (aria-busy or loading prompt)
  • When a modal opens, focus moves into the modal

Testing tools

# 自动检查
npx axe-core          # 静态分析
npx pa11y-ci          # CI 集成
npx lighthouse        # Chrome DevTools 中的 Accessibility 审计

# 手动测试
Tab 遍历页面          # 键盘导航是否有逻辑顺序?
VoiceOver / NVDA     # 屏幕阅读器能否理解页面?

Common claims

Claim Reality Consequence
"Add accessibility last" Start from the first component. Add last = never add = rewrite everything. Add last = the global DOM structure does not support keyboard navigation and ARIA, and the rework effort = rewriting 40-60% of the frontend. The project will never do it.
"Users are basically not people with disabilities" Accessibility also serves everyone: keyboard users, mobile, slow networks, temporary impairments (broken arm). (Accessibility improves the experience for all users) About 15% of the global population has some form of disability. Ignoring a11y = excluding 15% of potential users + legal compliance risk (ADA lawsuits average $50K+ in damages).
"As long as the automated checks pass, it's fine" aXe can detect about 30% of issues. Manual keyboard testing and manual screen reader testing are irreplaceable. The 70% that automated tools miss includes focus traps, semantic structure, and screen reader experience—these are the daily obstacles for real users.
"Using div is more convenient than using button" A div has no keyboard operation, no ARIA role, and no focus management. Use button. A button made with a div is completely inoperable for keyboard users and completely invisible to screen reader users—the functionality does not exist for them.
"Color distinction is enough" About 8% of men have some form of color vision deficiency. Information should never be conveyed by color alone. Users with color vision deficiency cannot see red error prompts → submit incorrect data → business process interruption. Distinction by color alone = functionality fails for 8% of users.

Violating the letter of the rule is violating the spirit. There is no gray area.

Output template

# Accessibility Audit Report — 可访问性审计报告

## 元信息
- **审查者**: [姓名/角色]
- **组件/页面**: [组件名或页面路径]
- **审查日期**: YYYY-MM-DD

## 自动检查结果
- **aXe**: [通过 / 发现 N 个违规] — 违规列表见下方
- **Lighthouse Accessibility**: [分数] — 最低准入: 90
- **pa11y-ci**: [通过 / 发现 N 个问题]

## 自动检查违规详情

| # | 规则 | 级别 | 位置 | 描述 | 修复状态 |
|---|------|------|------|------|---------|
| 1 | color-contrast | Critical | L42 | 文本对比度 2.8:1 < 4.5:1 | 🔴 待修复 |
| 2 | label | Critical | L78 | input #email 缺少 label | 🔴 待修复 |
| 3 | aria-valid-attr | Important | L91 | aria-label 值为空字符串 | 🟡 建议修复 |

## 手动检查结果

### 键盘导航
- [ ] Tab 顺序逻辑性: [通过 / 未通过 — 具体问题]
- [ ] 模态框焦点管理: [通过 / 未通过 — 具体问题]
- [ ] 所有交互元素键盘可达: [通过 / 未通过 — 具体问题]

### 屏幕阅读器
- [ ] 语义结构完整: [通过 / 未通过 — 具体问题]
- [ ] ARIA 标注正确: [通过 / 未通过 — 具体问题]
- [ ] 动态内容宣告: [通过 / 未通过 — 具体问题]

### 视觉
- [ ] 对比度达标: [通过 / 未通过 — 具体问题]
- [ ] 颜色不是唯一信息方式: [通过 / 未通过 — 具体问题]

## 审查结论
- **通过**: 自动检查评分 ≥ 90 + 手动检查全部通过
- **阻止**: Critical 违规未修复或手动检查关键流程失败

## 红旗 — STOP

- 只用颜色(红/绿)指示状态 —— 没文字、没图标
- 表单 input 没有 label(或 placeholder 作为唯一标签)
- 模态框打开后焦点没有移动进去
- Tab 顺序在视觉和逻辑上不一致
- 图像没有 alt(且不是装饰性的)
- 视频没有字幕
- `onClick` div 充当按钮(用 `<button>`)

## 验证失败处理

| 失败场景 | 处理方式 |
|---------|---------|
| aXe/Lighthouse 评分 < 90 | 标记具体违规项。逐条修复后重新运行自动检查。不得降级准入标准。 |
| 键盘无法完成主要流程 | 阻止交付。检查 Tab 顺序、焦点陷阱、交互元素键盘操作。修复后手动验证完整流程。 |
| 模态框焦点未正确管理 | 阻止交付。打开时焦点必须移入模态框、Tab 循环不逃逸、关闭时焦点回到触发元素。 |
| 表单 input 缺少 label | 阻止交付。每个 input 必须有 visible label 或 aria-label。placeholder 不可作为唯一标签。 |
| 颜色对比度 < 4.5:1(普通文本)| 调整颜色或增加辅助标识(图标、文字、边框)。对比度不达标 = 信息不可辨识。 |

## 验证清单

- [ ] Tab 顺序有逻辑性,所有交互元素可达
- [ ] 模态框焦点管理正确(进入+关回)
- [ ] 所有内容图像有 `alt`
- [ ] 颜色不是唯一信息传达方式
- [ ] 表单有 label、错误关联、必填指示
- [ ] aXe / Lighthouse Accessibility 审计通过(得分 ≥ 90)
- [ ] 键盘能完成主要用户流程