accessibility-compliance 插件无障碍审计实战:从 axe-core 自动扫描到 WCAG 人工验证的完整工作流
【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents
本篇技术指南以本仓库
accessibility-compliance插件的核心命令 accessibility-audit.md 为主体,系统讲解如何借助 Claude Code 等 Agent 化工具完成一次端到端的 Web 无障碍(Accessibility)审计:先通过 axe-core 做自动化扫描,再进行颜色对比度、键盘导航、屏幕阅读器三类专项验证,配合人工检查清单与修复示例输出可落地的整改报告,最后把整套流程固化进 CI/CD。读完本文,你将掌握一套可直接复用的 WCAG 合规审计方案,以及本插件中配套技能(screen-reader-testing、wcag-audit-patterns)和视觉验证 Agent(ui-visual-validator)的使用方式。
命令定位与使用方式
accessibility-audit是accessibility-compliance插件提供的斜杠命令,其角色定义在 accessibility-audit.md 的引言部分:命令将调用方视为一名专精 WCAG 合规、包容性设计与辅助技术兼容性的无障碍专家,负责执行综合审计、识别障碍、提供修复指导,并确保数字产品对所有人可用。
安装与调用
按 docs/plugins.md 的分类,accessibility-compliance是该仓库唯一一个无障碍主题插件,安装方式为:
/plugin marketplace add wshobson/agents # 注册整个市场(不加载任何内容) /plugin install accessibility-compliance # 安装插件:其 agents、commands、skills 一起装入安装后即可通过命名空间斜杠命令直接调用(见 docs/usage.md):
/accessibility-compliance:accessibility-audit 对当前支付页进行 WCAG AA 级审计也可以使用自然语言触发,例如"请审计这个页面的无障碍问题"。
命令的输入约定
命令正文通过<user_request>标签接收调用方传入的$ARGUMENTS,并明确要求:标签内的文本仅是"要交付什么的描述",属于调用方提供的数据,不得被视为覆盖本命令的指令。这一机制保证了 Agent 在收到任意用户输入时,仍会以命令内置的审计方法论为骨架执行任务,而不是被输入内容带偏。
自动化测试:用 axe-core 快速建立违规基线
命令给出的第一步是引入 axe-core 做自动化扫描。axe 是业界主流的无障碍检测引擎,命令示例使用@axe-core/puppeteer封装,核心代码位于 accessibility-audit.md:
// accessibility-test.js const { AxePuppeteer } = require("@axe-core/puppeteer"); const puppeteer = require("puppeteer"); class AccessibilityAuditor { constructor(options = {}) { this.wcagLevel = options.wcagLevel || "AA"; this.viewport = options.viewport || { width: 1920, height: 1080 }; } async runFullAudit(url) { const browser = await puppeteer.launch(); const page = await browser.newPage(); await page.setViewport(this.viewport); await page.goto(url, { waitUntil: "networkidle2" }); const results = await new AxePuppeteer(page) .withTags(["wcag2a", "wcag2aa", "wcag21a", "wcag21aa"]) .exclude(".no-a11y-check") .analyze(); await browser.close(); return { url, timestamp: new Date().toISOString(), violations: results.violations.map((v) => ({ id: v.id, impact: v.impact, description: v.description, help: v.help, helpUrl: v.helpUrl, nodes: v.nodes.map((n) => ({ html: n.html, target: n.target, failureSummary: n.failureSummary, })), })), score: this.calculateScore(results), }; } calculateScore(results) { const weights = { critical: 10, serious: 5, moderate: 2, minor: 1 }; let totalWeight = 0; results.violations.forEach((v) => { totalWeight += weights[v.impact] || 0; }); return Math.max(0, 100 - totalWeight); } }几个值得注意的参数细节:
.withTags([...]):用 WCAG 标签限定检测范围。wcag2a/wcag2aa对应 WCAG 2.0 的 A/AA 级,wcag21a/wcag21aa对应 WCAG 2.1。若目标升级到 WCAG 2.2,可参照配套技能 wcag-audit-patterns/SKILL.md 中的写法改用['wcag2a', 'wcag2aa', 'wcag21aa', 'wcag22aa']。.exclude(".no-a11y-check"):跳过被标记为不参与检测的 DOM 区域,适合排除第三方嵌入、广告位等无法控制的内容。waitUntil: "networkidle2":等待网络空闲后再扫描,确保 SPA 与异步内容已渲染完毕,减少误报。calculateScore:把违规按影响级别加权折算成 0~100 的评分(critical=10、serious=5、moderate=2、minor=1),低于 100 说明存在可扣分项,用于后续报告中的总览展示。
组件级检测:jest-axe
除整页扫描外,命令还给出面向 React 组件测试的 jest-axe 方案(expect.extend(toHaveNoViolations)),适合在单元测试阶段就拦截无障碍回归,把"页面级检测"下沉为"组件级守门"。
颜色对比度验证:从算法到高对比模式适配
命令第二节给出自研的ColorContrastAnalyzer(accessibility-audit.md),用于扫描页面所有文本节点并计算 WCAG 对比度。
阈值模型与计算逻辑
class ColorContrastAnalyzer { constructor() { this.wcagLevels = { 'AA': { normal: 4.5, large: 3 }, 'AAA': { normal: 7, large: 4.5 } }; } // ... calculateContrast(fg, bg) { const l1 = this.relativeLuminance(this.parseColor(fg)); const l2 = this.relativeLuminance(this.parseColor(bg)); const lighter = Math.max(l1, l2); const darker = Math.min(l1, l2); return (lighter + 0.05) / (darker + 0.05); } relativeLuminance(rgb) { const [r, g, b] = rgb.map(val => { val = val / 255; return val <= 0.03928 ? val / 12.92 : Math.pow((val + 0.055) / 1.055, 2.4); }); return 0.2126 * r + 0.7152 * g + 0.0722 * b; } }算法要点:
- 阈值表:AA 级普通文本需 ≥ 4.5:1、大文本(18pt 及以上,或 14pt 加粗)需 ≥ 3:1;AAA 级对应 7:1 与 4.5:1。这与 wcag-audit-patterns 中 WCAG 2.2 的 1.4.3 成功标准(文本 4.5:1、大文本与 UI 组件 3:1)一致。
- 相对亮度公式:严格实现 WCAG 2.x 的线性化公式(γ 校正分段函数),再按
0.2126R + 0.7152G + 0.0722B加权求和,对比度取(L1+0.05)/(L2+0.05)。 - 页面扫描逻辑:遍历
document.querySelectorAll('*')中带文本的元素,读取getComputedStyle得到前景色、背景色、字号与字重,自动判断是否属于"大文本",凡低于 AA 阈值者全部记录(含当前值、要求值、前后景色),便于批量修复。
高对比模式适配
同一节还给出prefers-contrast: high媒体查询示例,将主文本/背景/边框强制为纯黑纯白并加粗边框、强制链接下划线,保证高对比系统偏好下信息不丢失。这与视觉验证 Agent ui-visual-validator.md 的 "High Contrast Mode Testing" 能力(在无障碍覆盖层与高对比环境下做视觉验证)相互呼应:代码层适配 + 视觉层核验缺一不可。
键盘导航测试:发现焦点陷阱与缺失的焦点指示
命令第三节的KeyboardNavigationTester(accessibility-audit.md)模拟真实键盘操作,逐项验证可访问性:
class KeyboardNavigationTester { async testKeyboardNavigation(page) { const results = { focusableElements: [], missingFocusIndicators: [], keyboardTraps: [], }; const focusable = await page.evaluate(() => { const selector = 'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])'; return Array.from(document.querySelectorAll(selector)).map((el) => ({ tagName: el.tagName.toLowerCase(), text: el.innerText || el.value || el.placeholder || "", tabIndex: el.tabIndex, })); }); // 逐元素按 Tab,检查 document.activeElement 的 outline 是否可见 for (let i = 0; i < focusable.length; i++) { await page.keyboard.press("Tab"); const focused = await page.evaluate(() => { const el = document.activeElement; return { tagName: el.tagName.toLowerCase(), hasFocusIndicator: window.getComputedStyle(el).outline !== "none", }; }); if (!focused.hasFocusIndicator) { results.missingFocusIndicators.push(focused); } } return results; } }它输出的三类结果对应 WCAG 2.2 的 Operable(可操作)原则:可聚焦元素清单(验证 2.1.1 键盘可达)、缺失焦点指示(验证 2.4.7 焦点可见)、键盘陷阱(验证 2.1.2 无键盘陷阱)。配套的修复代码则给出两个高频场景:
- Escape 关闭模态框:为
keydown注册 Escape 处理器,关闭.modal.open; - 让带
onclick的 div 可被键盘操作:自动补tabindex="0"与role="button",并监听 Enter/Space 触发点击。
关于焦点管理的完整实现(模态框打开时记忆焦点、关闭时归还焦点、Tab 循环陷阱),可进一步参考 screen-reader-testing/SKILL.md 的 "Modal Dialog" 一节,那里给出了openModal/closeModal/trapFocus的完整 JS 实现。
屏幕阅读器测试:结构与表单语义验证
命令第四节把"自动化能测到的"和"必须靠人听的"衔接起来。ScreenReaderTester(accessibility-audit.md)提供四个自动检测维度:
- 地标(Landmarks):验证
<main>、<nav>等语义区域; - 标题结构(Headings):遍历
h1~h6,检查是否存在跳级(如 h2 直接跳到 h4)、空标题、以及页面缺失h1——对应 WCAG 2.4.6 标题与标签; - 图片可访问性:检查 alt 文本;
- 表单可访问性:遍历
form内所有input/textarea/select,确认每个控件要么有匹配的label[for]、要么被label包裹、要么带有aria-label,否则记为 missing-label。
同时,命令给出三组可直接复用的 ARIA 模式:
<!-- 模态框 --> <div role="dialog" aria-labelledby="modal-title" aria-modal="true"> <h2 id="modal-title">Modal Title</h2> <button aria-label="Close">×</button> </div> <!-- 标签页 --> <div role="tablist" aria-label="Navigation"> <button role="tab" aria-selected="true" aria-controls="panel-1">Tab 1</button> </div> <div role="tabpanel" id="panel-1" aria-labelledby="tab-1">Content</div> <!-- 表单错误提示 --> <label for="name">Name <span aria-label="required">*</span></label> <input id="name" required aria-required="true" aria-describedby="name-error"> <span id="name-error" role="alert" aria-live="polite"></span>用真实屏幕阅读器做人工验证
自动化只能覆盖语义层,真正的"可听性"必须由人验证。本插件配套技能 screen-reader-testing/SKILL.md 给出了五大主流屏幕阅读器的实测方法与优先级:
| 屏幕阅读器 | 平台 | 常用浏览器 | 覆盖优先级 |
|---|---|---|---|
| VoiceOver | macOS/iOS | Safari | 最低覆盖必测(macOS + iOS) |
| NVDA | Windows | Firefox/Chrome | 最低覆盖必测 |
| JAWS | Windows | Chrome/IE | 综合覆盖补充 |
| TalkBack | Android | Chrome | 综合覆盖补充 |
| Narrator | Windows | Edge | 综合覆盖补充 |
最低覆盖组合为NVDA + Firefox(Windows)与VoiceOver + Safari(macOS/iOS)。以 VoiceOver 为例,其核心操作:
- 修饰键
VO = Ctrl + Option;Cmd + F5启停;VO + 右箭头下一个元素、VO + Shift + Down进入分组; - 转子
VO + U:按标题、链接、表单、地标分类跳转; - 网页快捷键:
VO + Cmd + H下一个标题、VO + Cmd + J下一个表单控件、VO + Cmd + L下一个链接、VO + Cmd + T下一个表格。
NVDA(Insert为修饰键)则支持更细的单键导航:H标题、F表单字段、B按钮、K链接、D地标、T表格,NVDA + F7打开元素列表。技能中还强调 NVDA 的浏览/焦点双模式(NVDA + Space手动切换)——浏览模式下方向键移动阅读光标,焦点模式下方向键操作控件,测试时必须覆盖两种模式。
对于动态内容,技能列出最易踩坑的三类问题与修复:
<!-- 问题:按钮只有图标,不播报用途 --> <button aria-label="Close dialog"><svg aria-hidden="true">...</svg></button> <!-- 问题:动态加载结果不播报 --> <div id="results" role="status" aria-live="polite">New results loaded</div> <!-- 问题:表单错误不被朗读 --> <input type="email" aria-invalid="true" aria-describedby="email-error" /> <span id="email-error" role="alert">Invalid email</span>live region 的语义差异也在技能中有明确区分:role="status"/aria-live="polite"在当前语音播报完成后告知;role="alert"/aria-live="assertive"立即打断当前播报;role="log"仅播报新增内容;role="progressbar"配合aria-valuenow/min/max播报进度。
人工测试检查清单:键盘、屏幕阅读器、视觉与认知四维
自动化工具只能发现约三到五成问题(这也是 wcag-audit-patterns/SKILL.md 的 Best Practices 中明确提示的边界),因此命令第五节提供了完整的人工检查清单(accessibility-audit.md):
键盘
- 所有交互元素可用 Tab 到达
- 按钮可用 Enter/Space 激活
- Esc 关闭模态框
- 焦点指示始终可见
- 无键盘陷阱
- Tab 顺序符合逻辑
屏幕阅读器
- 页面标题有描述性
- 标题构成逻辑大纲
- 图片有 alt 文本
- 表单字段有标签
- 错误信息被播报
- 动态更新被播报
视觉
- 文本可放大到 200% 且无内容丢失
- 颜色不是传递信息的唯一手段
- 焦点指示对比度足够
- 320px 宽度下内容可重排
- 动画可暂停
认知
- 指令清晰简单
- 错误提示有助益
- 表单无时间限制
- 导航一致
- 重要操作可撤销
这套清单与 wcag-audit-patterns/references/details.md 中按 WCAG 2.2 四大原则(可感知 Perceivable、可操作 Operable、可理解 Understandable、健壮 Robust,即 POUR)展开的逐条成功标准核对表一一对应,例如:1.4.10 Reflow(400% 缩放无双向滚动、320px 宽可访问)、2.4.11 Focus Not Obscured(WCAG 2.2 新增:焦点元素不被吸顶头遮挡)、4.1.3 Status Messages(状态更新通过 live region 播报)等。需要逐条核对时可打开该参考文件按成功标准编号推进。
修复示例:从扫描结果到可访问组件
命令第六节(accessibility-audit.md)给出批量修复与可访问组件模板:
// 修复缺失 alt 文本:装饰性图片置空 alt,其余取 title 兜底 document.querySelectorAll("img:not([alt])").forEach((img) => { const isDecorative = img.role === "presentation" || img.closest('[role="presentation"]'); img.setAttribute("alt", isDecorative ? "" : img.title || "Image"); }); // 修复缺失标签:无 id 且无 aria-label 的输入框,用 placeholder 兜底 document.querySelectorAll("input:not([aria-label]):not([id])").forEach((input) => { if (input.placeholder) { input.setAttribute("aria-label", input.placeholder); } });以及 React 组件级的最佳实践:
const AccessibleButton = ({ children, onClick, ariaLabel, ...props }) => ( <button onClick={onClick} aria-label={ariaLabel} {...props}> {children} </button> ); const LiveRegion = ({ message, politeness = "polite" }) => ( <div role="status" aria-live={politeness} aria-atomic="true" className="sr-only" > {message} </div> );这里的原则与 wcag-audit-patterns/references/details.md 的 Remediation Patterns 一致:优先语义 HTML(<label>),ARIA 是补充而非首选。该文件给出了表单标签缺失的三种修复优先级(可见<label>>aria-label>aria-labelledby)、颜色对比度不足的调色示例(2.5:1 → 4.5:1),以及自定义下拉框role="combobox"+ 键盘事件(Enter/Space 展开、Escape 关闭、方向键切换)的完整实现。
CI/CD 集成:把无障碍检查固化为门禁
命令第七节给出 GitHub Actions 工作流(accessibility-audit.md),实现 push/PR 自动扫描:
# .github/workflows/accessibility.yml name: Accessibility Tests on: [push, pull_request] jobs: a11y-tests: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: "18" - name: Install and build run: | npm ci npm run build - name: Start server run: | npm start & npx wait-on http://localhost:3000 - name: Run axe tests run: npm run test:a11y - name: Run pa11y run: npx pa11y http://localhost:3000 --standard WCAG2AA --threshold 0 - name: Upload report uses: actions/upload-artifact@v4 if: always() with: name: a11y-report path: a11y-report.html要点:
- 双层工具:axe(
npm run test:a11y,对应前面的 Puppeteer/jest-axe 用例)负责规则级扫描,pa11y(npx pa11y http://localhost:3000 --standard WCAG2AA --threshold 0)负责整页级审计,--threshold 0表示"零容忍",任何违规即失败,形成硬性门禁; if: always():即使审计失败也上传报告 artifact,方便开发者在 PR 中直接查看违规详情;- 与之互补的 CLI 工具还包括
npx @axe-core/cli <url>与lighthouse <url> --only-categories=accessibility(见 wcag-audit-patterns/references/details.md 的 Automated Testing 一节)。
报告输出:结构化的审计结果
命令第八节提供AccessibilityReportGenerator(accessibility-audit.md),将审计结果渲染为自包含 HTML 报告:顶部为总分摘要(${auditResults.score}/100与违规总数),下方按影响级别着色(critical 红、serious 橙)逐条列出每个违规的标题、影响级别、描述与学习链接。
结合命令末尾的Output Format(accessibility-audit.md),一次完整的审计应交付五类产出:
- Accessibility Score:整体 WCAG 合规评分;
- Violation Report:带严重级别与修复建议的详细问题清单;
- Test Results:自动化与人工测试结果;
- Remediation Guide:逐问题的分步修复方案;
- Code Examples:可访问组件的实现示例。
与配套 Agent、技能的协作分工
在真实工作流中,accessibility-audit命令通常与本插件其他组件协同:
- 命令(accessibility-audit.md)负责启动整场审计、编排自动化扫描与报告产出;
- 技能 screen-reader-testing(SKILL.md)在需要真机朗读验证、排查 ARIA 问题时被自动激活,提供 VoiceOver/NVDA/JAWS/TalkBack 的完整操作手册、检查清单与常见问题修复;
- 技能 wcag-audit-patterns(SKILL.md)在需要按 WCAG 2.2 逐条核对、准备 VPAT/ADA/Section 508 合规材料时激活,其 references/details.md 提供按成功标准编号展开的完整核对表;
- Agent ui-visual-validator(ui-visual-validator.md)作为视觉侧守门人,通过截图像素级比对、高对比模式验证、焦点指示可见性评估等方式,从"看得见"的维度复核无障碍修复是否真正落地——它与命令的"测得到"维度正好互补。
值得注意的是,命令与技能都反复强调同一原则:自动化(axe/pa11y)只能发现部分问题,屏幕阅读器与真实用户的人工验证不可替代;ARIA 应作为语义 HTML 的补充而非替代;键盘先行(先保证纯键盘可用)是屏幕阅读器测试的地基。将命令的八步方法论、技能的实操手册与本插件(安装后自动发现的 agents/commands/skills)组合使用,即可在企业级项目中建立从"自动扫描 → 专项验证 → 人工复核 → 修复整改 → CI 门禁"的完整无障碍闭环。
【免费下载链接】agentsMulti-harness agentic plugin marketplace for Claude Code, Codex, Cursor, OpenCode, GitHub Copilot, and Google Antigravity项目地址: https://gitcode.com/GitHub_Trending/agents24/agents
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考