axe-core是CI中可访问性断言的首选,因其是断言型工具,可直接抛错中断构建、支持细粒度规则开关、适配多种DOM环境、错误定位精准到CSS选择器路径,且易于集成Jest/Vitest等测试框架。

自动化测试不能替代手动可访问性审计,但它能稳定拦截 70% 以上的基础 WCAG 违规项——关键在于选对工具、在对的环节运行、并理解它的盲区。
为什么 axe-core 是 CI 中可访问性断言的首选
axe-core 不是生成报告的“旁观者”,而是能直接让构建失败的“守门员”。它支持细粒度规则开关、可注入任意 DOM 环境(JSDOM / Playwright page / 真实浏览器),且错误定位精准到 violation.nodes[0].target(一个 CSS 选择器路径)。
- 别用
Lighthouse做 CI 断言:它默认不因可访问性低分失败,必须额外配lhci规则,启动 Chromium 开销大,且报告里常只写“element with role=button”,没法准确定位具体哪个节点 -
axe.run()返回的是结构化 JSON,你可以直接判断results.violations.length > 0并抛错,和 Jest/Vitest 的expect无缝衔接 - 规则集建议从
wcag2aa启动,再按项目加color-contrast(需注意字体加载时机)、heading-order等高价值项
Playwright 测试中嵌入 axe-core 的实操要点
不是调用 page.accessibility.snapshot() 就算做了可访问性测试——那只是取快照,不执行 WCAG 规则校验。真正在 E2E 中守门,得把 axe 注入页面上下文执行完整扫描。
- 安装后,在 test 文件里
import axe from 'axe-core',再用await page.addScriptTag({ path: require.resolve('axe-core') })注入 - 执行前务必等 hydration 完成:
await page.waitForFunction(() => document.querySelector('#root')?.children.length > 0) - 若页面用了自定义字体,加
await page.waitForFunction(() => document.fonts.check('1em "Inter"')),否则color-contrast会误报 - 断言写法推荐:
expect(results.violations).toHaveLength(0);失败时打印results.violations.map(v => v.help)快速定位问题类型
CI 环境下 axe 扫描失真的三个典型原因
本地全绿、CI 突然爆一堆 color-contrast 或 heading-order 错误?大概率不是代码退化,而是环境差异导致 axe 看到的 DOM 和你本地不一致。
立即学习“前端免费学习笔记(深入)”;
- 字体未就绪:CI 容器里字体加载慢或缺失,
getComputedStyle返回默认值,触发对比度误判 - CSS 未完全应用:样式表异步加载、
media="print"被忽略、或关键 CSS 被 purge 导致结构渲染异常 - 动态内容未稳定:React/Vue 组件内有微任务延迟渲染(如
useEffect里 setState),axe 扫描时 DOM 还没更新完
真正难的不是跑通 axe,而是让每次扫描看到的 DOM 状态可预期——这需要你在测试脚本里显式控制字体加载、CSS 就绪、hydration 完成、数据稳定四个关键节点,缺一不可。



















