axe-core是ci中可访问性检查的唯一合理选择,因其为断言型工具,可直接抛错中断构建、支持细粒度规则开关、适配多种dom环境、错误定位精准到css选择器路径,且易于集成jest/vitest等测试框架;而lighthouse是报告型工具,需额外配置、资源开销大、不可裁剪且难以对齐现有测试。

axe-core 是 CI 中可访问性检查的唯一合理选择
别用 Lighthouse 做可访问性门禁。它默认不因 a11y 问题失败,必须额外配 lhci assert 规则、启动 Chromium 实例、上传报告——CI 资源开销大,失败定位模糊,且和 Jest/Vitest 测试套件脱节。而 axe-core 是断言型工具:调用 axe.run() 后直接检查 results.violations.length > 0,就能让构建立刻中断。
它支持注入 JSDOM、Playwright page 或真实浏览器上下文;错误精准到 violation.nodes[0].target(CSS 选择器路径);规则可按需开关,比如只启用 "wcag2aa",不强制扫描所有 WCAG 3.0 新规。
在 Playwright 测试里嵌入 axe-core 的最小可行写法
手写 page.accessibility.snapshot() 没用,它只返回基础属性,不执行 WCAG 规则校验。真正在 E2E 场景做守门,得把 axe-core 注入页面并运行完整扫描:
- 安装:
npm install axe-core - 注入脚本:
await page.addScriptTag({ path: require.resolve('axe-core') }) - 等 hydration 完成(React/Vue 应用必需):
await page.waitForFunction(() => document.querySelector('#root')?.children.length > 0) - 执行扫描:
const results = await page.evaluate(() => (window as any).axe.run()) - 断言:
expect(results.violations).toHaveLength(0),失败时打印results.violations.map(v => v.help)快速定位
CI 环境下 axe-core 扫描失真的三个硬坑
本地全绿、CI 突然报一堆 color-contrast 或 heading-order 错误?不是代码退化,而是环境差异导致 axe 看到的 DOM 和你本地不一样:
- 字体未就绪:
getComputedStyle拿不到真实字号/颜色,加await page.waitForFunction(() => document.fonts.check('1em "Inter"')) - CSS 未加载完成:确保
page.goto(url, { waitUntil: 'networkidle' }),而非'domcontentloaded' - 动态内容未渲染:如 CMS 注入的富文本、第三方 widget,需显式
await page.waitForSelector('.cms-content')或类似条件
html-validate + axe-core 必须分层配合
html-validate 检源码结构(缺 alt、错嵌套、非法属性),axe-core 检运行时可访问性(对比度、焦点顺序、ARIA 层级)。两者不能互相替代:
-
html-validate不知道aria-hidden="true"是否被滥用,axe-core也看不到模板里漏写的img-alt - CI 中必须同时跑:
npx html-validate --config .htmlvalidate.json src/**/*.html和 Playwright + axe 测试 - 注意
html-validate默认不校验data-属性,若用 Web Components,需在配置中启用no-unknown-attributes插件
真正卡住问题的,从来不是单点工具,而是源码层 + 运行时层的双重拦截。axe-core 在 CI 里扫出的每个 violation,都对应一个真实用户可能遇到的障碍——这点容易被忽略,但恰恰是自动化可访问性检查存在的唯一理由。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











