a11y-audit

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

RGAA 4.1.2 Runtime Accessibility Auditor

RGAA 4.1.2 运行时可访问性审计工具

Audit live pages for RGAA 4.1.2 compliance using Playwright and axe-core. Complements
a11y-web
(static code) with runtime checks that require a rendered browser environment: real contrast ratios, dynamic content, focus order, and more.
使用Playwright和axe-core对在线页面进行RGAA 4.1.2合规性审计。补充
a11y-web
(静态代码审计)的功能,提供需要渲染浏览器环境的运行时检查:真实对比度、动态内容、焦点顺序等。

When to Use This Skill

何时使用该技能

  • User provides a sitemap URL (e.g.,
    https://site.com/sitemap.xml
    )
  • User provides a list of URLs to audit
  • User wants to audit a deployed site (staging or production)
  • User asks to "check a11y on production", "audit live pages", "run RGAA on the site"
For source code analysis, use
a11y-web
instead.

  • 用户提供站点地图URL(例如:
    https://site.com/sitemap.xml
  • 用户提供待审计的URL列表
  • 用户希望审计已部署站点(staging或生产环境)
  • 用户提出类似“check a11y on production”、“audit live pages”、“run RGAA on the site”的需求
如需源代码分析,请使用
a11y-web

Dependencies

依赖项

This skill requires Playwright and axe-core. Verify they are available before running.
bash
undefined
该技能需要Playwright和axe-core。运行前请确认它们已可用。
bash
undefined

Check Playwright

检查Playwright版本

npx playwright --version
npx playwright --version

Check axe-core (used via CDN injection — no local install needed)

检查axe-core(通过CDN注入使用,无需本地安装)

OR install locally:

或本地安装:

npm install --save-dev axe-core

If Playwright is not installed, run the setup script:
```bash
bash skills/a11y-audit/scripts/setup.sh
The setup script installs Playwright and verifies the environment. See
scripts/setup.sh
for details.

npm install --save-dev axe-core

如果未安装Playwright,请运行安装脚本:
```bash
bash skills/a11y-audit/scripts/setup.sh
该安装脚本会安装Playwright并验证环境。详情请查看
scripts/setup.sh

Modes

模式

Single URL

单个URL

Audit one page. User provides:
https://example.com/page
审计单个页面。用户提供:
https://example.com/page

Sitemap Audit (default)

站点地图审计(默认)

Fetch sitemap XML → extract URLs → audit each page in sequence. User provides:
https://example.com/sitemap.xml
获取站点地图XML → 提取URL → 依次审计每个页面。 用户提供:
https://example.com/sitemap.xml

URL List

URL列表

User provides a list of URLs (file or inline).

用户提供URL列表(文件或内联形式)。

Workflow

工作流程

Step 0 — Verify Playwright

步骤0 — 验证Playwright

undefined
undefined

Ensure Playwright browser is available

确保Playwright浏览器可用

mcp__playwright__browser_install (if needed)

If browser install fails, report the error and stop. Do not proceed without a working browser.
mcp__playwright__browser_install (如有需要)

如果浏览器安装失败,报告错误并停止。浏览器不可用时请勿继续。

Step 1 — Get URL List

步骤1 — 获取URL列表

From sitemap:
WebFetch: GET [sitemap_url]
Parse the XML response to extract
<loc>
elements.
javascript
// Sitemap parsing — extract URLs
const urls = xmlContent.match(/<loc>(.*?)<\/loc>/g)
  .map(loc => loc.replace(/<\/?loc>/g, '').trim());
For large sitemaps (> 50 URLs): audit the first 20 by default, or the N pages specified by the user. Large sitemaps may have nested sitemaps (
<sitemap>
elements) — follow them recursively up to one level.
From URL list: use as-is.
From single URL: wrap in array.
从站点地图获取:
WebFetch: GET [sitemap_url]
Parse the XML response to extract
<loc>
elements.
javascript
// 站点地图解析 — 提取URL
const urls = xmlContent.match(/<loc>(.*?)<\/loc>/g)
  .map(loc => loc.replace(/<\/?loc>/g, '').trim());
对于大型站点地图(超过50个URL):默认审计前20个页面,或用户指定的N个页面。大型站点地图可能包含嵌套站点地图(
<sitemap>
元素)—— 递归跟进一级嵌套。
从URL列表获取: 直接使用。
从单个URL获取: 包装为数组。

Step 2 — For Each Page: Navigate and Audit

步骤2 — 对每个页面:导航并审计

For each URL, execute Steps 2a–2e in sequence.
对每个URL,依次执行步骤2a至2e。

2a — Navigate

2a — 导航

browser_navigate: url
browser_wait_for: { state: "load" }
If navigation fails (timeout, 404, auth redirect), mark page as
[SKIP]
and continue.
browser_navigate: url
browser_wait_for: { state: "load" }
如果导航失败(超时、404、授权重定向),标记页面为
[SKIP]
并继续。

2b — Inject and Run axe-core

2b — 注入并运行axe-core

javascript
// browser_evaluate — inject axe-core
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js';
document.head.appendChild(script);
await new Promise((resolve, reject) => {
  script.onload = resolve;
  script.onerror = reject;
  setTimeout(reject, 5000);
});
javascript
// browser_evaluate — run axe with WCAG 2.1 AA (covers most RGAA criteria)
const results = await axe.run(document, {
  runOnly: {
    type: 'tag',
    values: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice']
  }
});
return {
  violations: results.violations,
  passes: results.passes.length,
  incomplete: results.incomplete.length
};
If axe-core CDN fails (e.g., network restrictions), try loading from local node_modules:
javascript
// Fallback — inline axe-core from local install
// (only if npm install axe-core was run)
javascript
// browser_evaluate — 注入axe-core
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/ajax/libs/axe-core/4.10.2/axe.min.js';
document.head.appendChild(script);
await new Promise((resolve, reject) => {
  script.onload = resolve;
  script.onerror = reject;
  setTimeout(reject, 5000);
});
javascript
// browser_evaluate — 使用WCAG 2.1 AA标准运行axe(覆盖大多数RGAA准则)
const results = await axe.run(document, {
  runOnly: {
    type: 'tag',
    values: ['wcag2a', 'wcag2aa', 'wcag21a', 'wcag21aa', 'best-practice']
  }
});
return {
  violations: results.violations,
  passes: results.passes.length,
  incomplete: results.incomplete.length
};
如果axe-core CDN加载失败(例如网络限制),尝试从本地node_modules加载:
javascript
// 备选方案 — 从本地安装的axe-core内联加载
// (仅在运行npm install axe-core后可用)

2c — Custom DOM Queries (RGAA gaps in axe-core)

2c — 自定义DOM查询(axe-core未覆盖的RGAA准则)

axe-core does not cover all RGAA criteria. Run these additional checks:
javascript
// browser_evaluate — custom RGAA checks
const customChecks = {
  // RGAA 8.3 — lang attribute value
  langValue: document.documentElement.lang,

  // RGAA 9.1 — heading hierarchy
  headings: Array.from(document.querySelectorAll('h1,h2,h3,h4,h5,h6'))
    .map(h => ({ level: parseInt(h.tagName[1]), text: h.textContent.trim().slice(0, 60) })),

  // RGAA 12.7 — skip link: first focusable element
  firstFocusable: (() => {
    const el = document.querySelector(
      'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])'
    );
    return el ? { tag: el.tagName, href: el.getAttribute('href'), text: el.textContent.trim().slice(0, 60) } : null;
  })(),

  // RGAA 12.6 — landmark presence
  landmarks: {
    main: !!document.querySelector('main, [role="main"]'),
    nav: document.querySelectorAll('nav, [role="navigation"]').length,
    header: !!document.querySelector('header, [role="banner"]'),
    footer: !!document.querySelector('footer, [role="contentinfo"]')
  },

  // RGAA 11.1 — inputs without labels
  unlabeledInputs: Array.from(
    document.querySelectorAll('input:not([type="hidden"]):not([aria-label]):not([aria-labelledby])')
  ).filter(input => {
    const id = input.id;
    return !id || !document.querySelector(`label[for="${id}"]`);
  }).map(i => ({ type: i.type, name: i.name, id: i.id })),

  // RGAA 8.5 — page title
  title: document.title,

  // RGAA 3.1 — inputs/spans with only color-based class names (heuristic)
  colorOnlyIndicators: Array.from(
    document.querySelectorAll('[class*="red"],[class*="green"],[class*="error"],[class*="success"]')
  ).filter(el => !el.textContent.trim()).length,

  // RGAA 5.4 — tables without caption
  tablesWithoutCaption: Array.from(document.querySelectorAll('table'))
    .filter(t => !t.querySelector('caption') && t.getAttribute('role') !== 'presentation')
    .length,

  // RGAA 1.1 — images without alt
  imgsWithoutAlt: Array.from(document.querySelectorAll('img:not([alt])'))
    .map(i => i.src.split('/').pop())
};
return customChecks;
axe-core未覆盖所有RGAA准则。运行以下额外检查:
javascript
// browser_evaluate — 自定义RGAA检查
const customChecks = {
  // RGAA 8.3 — lang属性值
  langValue: document.documentElement.lang,

  // RGAA 9.1 — 标题层级
  headings: Array.from(document.querySelectorAll('h1,h2,h3,h4,h5,h6'))
    .map(h => ({ level: parseInt(h.tagName[1]), text: h.textContent.trim().slice(0, 60) })),

  // RGAA 12.7 — 跳过链接:第一个可聚焦元素
  firstFocusable: (() => {
    const el = document.querySelector(
      'a[href], button, input, select, textarea, [tabindex]:not([tabindex="-1"])'
    );
    return el ? { tag: el.tagName, href: el.getAttribute('href'), text: el.textContent.trim().slice(0, 60) } : null;
  })(),

  // RGAA 12.6 — 地标元素存在性
  landmarks: {
    main: !!document.querySelector('main, [role="main"]'),
    nav: document.querySelectorAll('nav, [role="navigation"]').length,
    header: !!document.querySelector('header, [role="banner"]'),
    footer: !!document.querySelector('footer, [role="contentinfo"]')
  },

  // RGAA 11.1 — 无标签的输入框
  unlabeledInputs: Array.from(
    document.querySelectorAll('input:not([type="hidden"]):not([aria-label]):not([aria-labelledby])')
  ).filter(input => {
    const id = input.id;
    return !id || !document.querySelector(`label[for="${id}"]`);
  }).map(i => ({ type: i.type, name: i.name, id: i.id })),

  // RGAA 8.5 — 页面标题
  title: document.title,

  // RGAA 3.1 — 仅含颜色类名的输入框/span(启发式检查)
  colorOnlyIndicators: Array.from(
    document.querySelectorAll('[class*="red"],[class*="green"],[class*="error"],[class*="success"]')
  ).filter(el => !el.textContent.trim()).length,

  // RGAA 5.4 — 无标题的表格
  tablesWithoutCaption: Array.from(document.querySelectorAll('table'))
    .filter(t => !t.querySelector('caption') && t.getAttribute('role') !== 'presentation')
    .length,

  // RGAA 1.1 — 无alt属性的图片
  imgsWithoutAlt: Array.from(document.querySelectorAll('img:not([alt])'))
    .map(i => i.src.split('/').pop())
};
return customChecks;

2d — Screenshot

2d — 截图

browser_take_screenshot: { fullPage: false }
Save for reference in the report (optional, activated by
--screenshots
flag).
browser_take_screenshot: { fullPage: false }
保存截图供报告参考(可选,通过
--screenshots
flag激活)。

2e — Get Accessibility Tree

2e — 获取可访问性树

browser_snapshot
Use to verify landmark structure and heading hierarchy in the rendered tree.
browser_snapshot
用于验证渲染树中的地标结构和标题层级。

Step 3 — Build Per-Page Report

步骤3 — 构建单页报告

For each page, produce a structured section:
markdown
undefined
对每个页面,生成结构化报告章节:
markdown
undefined

Page: [URL]

页面: [URL]

Status: 200 OK | Audited at: YYYY-MM-DD HH:MM
状态: 200 OK | 审计时间: YYYY-MM-DD HH:MM

axe-core Violations

axe-core 违规项

RGAAaxe RuleSeverityElementMessage
3.2color-contrastcritical
<p class="subtitle">
Contrast ratio 2.8:1 (min 4.5:1)
1.1image-altcritical
<img src="hero.jpg">
Missing alt attribute
12.7skip-linkmoderateNo skip navigation link found
RGAAaxe规则严重程度元素消息
3.2color-contrastcritical
<p class="subtitle">
对比度2.8:1(最低要求4.5:1)
1.1image-altcritical
<img src="hero.jpg">
缺少alt属性
12.7skip-linkmoderate未找到跳过导航链接

Custom RGAA Checks

自定义RGAA检查

  • [PASS] RGAA 8.3 — lang="fr" ✓
  • [FAIL] RGAA 9.1 — Heading hierarchy: h1 → h3 (h2 missing)
  • [FAIL] RGAA 12.6 — No <main> landmark found
  • [PASS] RGAA 12.7 — Skip link present: "Aller au contenu" → #main
  • [FAIL] RGAA 11.1 — 2 unlabeled inputs: input[type=email], input[type=search]
  • [通过] RGAA 8.3 — lang="fr" ✓
  • [失败] RGAA 9.1 — 标题层级: h1 → h3(缺少h2)
  • [失败] RGAA 12.6 — 未找到<main>地标元素
  • [通过] RGAA 12.7 — 存在跳过链接: "Aller au contenu" → #main
  • [失败] RGAA 11.1 — 2个无标签输入框: input[type=email], input[type=search]

Summary

摘要

  • axe-core violations: X (Y critical, Z serious, W moderate)
  • Custom RGAA failures: N
  • axe-core passes: P checks passed
  • Incomplete (needs manual review): I

Severity mapping (axe-core → RGAA):
- `critical` → `[FAIL]`
- `serious` → `[FAIL]`
- `moderate` → `[WARN]`
- `minor` → `[WARN]`
  • axe-core违规项: X(Y个critical,Z个serious,W个moderate)
  • 自定义RGAA检查失败: N
  • axe-core通过项: P项检查通过
  • 待手动审核: I

严重程度映射(axe-core → RGAA):
- `critical` → `[失败]`
- `serious` → `[失败]`
- `moderate` → `[警告]`
- `minor` → `[警告]`

Step 4 — Global Summary Report

步骤4 — 全局摘要报告

After all pages are audited, produce a consolidated report:
markdown
undefined
完成所有页面审计后,生成综合报告:
markdown
undefined

RGAA 4.1.2 Accessibility Audit Report

RGAA 4.1.2 可访问性审计报告

Site: [base URL] Sitemap: [sitemap URL] Date: YYYY-MM-DD Pages audited: N / Total in sitemap
站点: [基础URL] 站点地图: [站点地图URL] 日期: YYYY-MM-DD 已审计页面数: N / 站点地图总页面数

Critical Issues (across all pages)

严重问题(所有页面)

RGAAIssueOccurrencesPages affected
3.2Insufficient contrast4712/20 pages
1.1Missing alt on images238/20 pages
12.6Missing <main> landmark32/20 pages
RGAA问题出现次数受影响页面数
3.2对比度不足4712/20页面
1.1图片缺少alt属性238/20页面
12.6缺少<main>地标元素32/20页面

Per-Page Summary

单页摘要

PageViolationsCriticalWarningsStatus
/home1239
/about000
/contact523
页面违规项严重警告状态
/home1239
/about000
/contact523

Compliance Estimate

合规性估算

Estimated RGAA compliance rate: XX% (based on auditable criteria)
RGAA合规率估算: XX%(基于可审计准则)

Recommended Priority Actions

推荐优先操作

  1. Fix contrast issues (affects X% of users, critical severity, XX occurrences)
  2. Add alt text to images (XX occurrences on X pages)
  3. Add <main> landmark to layout template (affects all pages)
  1. 修复对比度问题(影响X%用户,严重级别,XX次出现)
  2. 为图片添加alt文本(X个页面出现XX次)
  3. 为布局模板添加<main>地标元素(影响所有页面)

Limitations

局限性

  • Interactive content (modals, tooltips, carousels) requires manual testing
  • Authentication-protected pages were skipped
  • Dynamic content loaded after interaction not audited
  • Recommended: complement with manual screen reader testing (NVDA/JAWS/VoiceOver)

Save the report to a file:
Write: a11y-audit-report-YYYY-MM-DD.md

---
  • 交互式内容(模态框、提示框、轮播)需要手动测试
  • 受身份验证保护的页面已跳过
  • 交互后加载的动态内容未被审计
  • 建议:结合手动屏幕阅读器测试(NVDA/JAWS/VoiceOver)

将报告保存到文件:
Write: a11y-audit-report-YYYY-MM-DD.md

---

axe-core → RGAA Mapping

axe-core → RGAA 映射表

RGAA Criterionaxe-core Rule(s)
1.1 — Image alt
image-alt
,
role-img-alt
,
input-image-alt
1.2 — Decorative images
image-redundant-alt
3.2 — Contrast
color-contrast
,
color-contrast-enhanced
6.1 — Link names
link-name
,
duplicate-link
6.2 — Image links
image-alt
(on img inside a)
8.3 — HTML lang
html-has-lang
,
html-lang-valid
8.4 — Lang valid
html-lang-valid
,
valid-lang
8.5 — Page title
document-title
9.1 — Headings
heading-order
,
page-has-heading-one
11.1 — Form labels
label
,
label-content-name-mismatch
11.2 — Placeholder
label
(no-label),
placeholder-label-no-duplicate
(best-practice)
11.5 — Fieldset
radiogroup
,
checkboxgroup
(best-practice)
12.1 — Multiple nav— (custom check)
12.6 — Landmarks
landmark-one-main
,
region
,
landmark-unique
12.7 — Skip link
skip-link
12.8 — Skip link functional
skip-link
Criteria not covered by axe-core (custom checks handle these):
  • RGAA 3.1 — Color-only information (heuristic only)
  • RGAA 9.1 — Heading level skip detection
  • RGAA 12.6 — Multiple nav without aria-label

RGAA准则axe-core规则
1.1 — 图片alt
image-alt
,
role-img-alt
,
input-image-alt
1.2 — 装饰性图片
image-redundant-alt
3.2 — 对比度
color-contrast
,
color-contrast-enhanced
6.1 — 链接名称
link-name
,
duplicate-link
6.2 — 图片链接
image-alt
(a标签内的img元素)
8.3 — HTML lang属性
html-has-lang
,
html-lang-valid
8.4 — lang属性有效性
html-lang-valid
,
valid-lang
8.5 — 页面标题
document-title
9.1 — 标题
heading-order
,
page-has-heading-one
11.1 — 表单标签
label
,
label-content-name-mismatch
11.2 — 占位符
label
(无标签),
placeholder-label-no-duplicate
(最佳实践)
11.5 — Fieldset
radiogroup
,
checkboxgroup
(最佳实践)
12.1 — 多个导航—(自定义检查)
12.6 — 地标元素
landmark-one-main
,
region
,
landmark-unique
12.7 — 跳过链接
skip-link
12.8 — 跳过链接功能
skip-link
axe-core未覆盖的准则(由自定义检查处理):
  • RGAA 3.1 — 仅含颜色信息(仅启发式检查)
  • RGAA 9.1 — 标题层级跳跃检测
  • RGAA 12.6 — 无aria-label的多个导航

Limitations

局限性

What cannot be audited automaticallyWhy
Authentication-protected pagesRequires login — provide session cookies if needed
Dynamic content (modals, live regions)Requires interaction to trigger
PDF / Office documentsNot browser-renderable
Video captions (RGAA topic 4)Requires human review
Touch target sizesRequires device-specific testing
Screen reader announcementsRequires real AT (NVDA, JAWS, VoiceOver)
For thorough RGAA compliance, complement this audit with:
  1. a11y-web
    — static source code analysis
  2. Manual screen reader walkthrough (NVDA/Firefox, VoiceOver/Safari)
  3. Keyboard-only navigation test

无法自动审计的内容原因
受身份验证保护的页面需要登录 — 如有需要请提供会话cookie
动态内容(模态框、实时区域)需要交互触发
PDF / Office文档无法在浏览器中渲染
视频字幕(RGAA第4主题)需要人工审核
触摸目标尺寸需要特定设备测试
屏幕阅读器播报需要真实辅助技术(NVDA, JAWS, VoiceOver)
如需全面的RGAA合规性,建议结合以下审计方式:
  1. a11y-web
    — 静态源代码分析
  2. 手动屏幕阅读器遍历测试(NVDA/Firefox, VoiceOver/Safari)
  3. 纯键盘导航测试

Reference

参考链接