CI中可访问性问题不报,主因是axe-core未在真实浏览器中运行、htmlhint规则未启用且退出码被忽略;必须用Puppeteer/Playwright启动Chromium,等待hydration完成,逐路由扫描,并断言violations为零。

CI 中不报可访问性问题,大概率不是没工具,而是工具没开、规则没生效、退出码被吞了——三者缺一不可。
axe-core 必须在真实浏览器环境运行
静态分析工具(如 htmlhint)根本看不到 JS 动态插入的 DOM,也识别不了 aria-hidden 误用、焦点顺序错乱、对比度不足等 WCAG 关键问题。axe-core 是唯一能在 CI 中真正落地 a11y 断言的工具,但它必须运行在浏览器里。
- 别用 JSDOM:它不支持完整无障碍树,
axe.run()返回结果大量漏报,尤其是color-contrast和heading-order - Puppeteer 或 Playwright 是最低成本选择;CI 中启动 Chromium 实例比 Lighthouse 轻量,且可精确控制页面加载时机
- 必须等 hydration 完成再扫描:React/Vue 应用要加
await page.waitForFunction(() => document.querySelector('#root')?.children.length > 0),否则扫到空壳 DOM - 关键路由逐个跑:首页、登录页、表单页不能只扫一个 URL,每个页面单独
page.goto()+axe.run(),避免遗漏
htmlhint 的 a11y 规则默认不启用
htmlhint 不是开了就管用。它的 img-alt-req 和 input-requires-label 这类可访问性规则,默认值是 false,不显式配置等于没写。
使用Playwright API直接进行浏览器自动化。导航网站、与元素交互、提取数据、截图、生成PDF、录制视频,自动化复杂工作流程。比MCP方法更可靠。
- 在
.htmlhintrc中必须明确设为true:"img-alt-req": true、"input-requires-label": true - CI 中常见静默失败:命令写成
npx htmlhint **/*.html || true,错误直接被吞掉;删掉|| true,让非零退出码中断构建 - 警告不算错:HTMLHint 默认 warning 不触发失败,加
--fail-on-warn参数,或在配置里设"failOnError": true(注意部分版本默认是false) - 路径通配符要严谨:用
src/**/*.html,别用**/*.html,否则会扫进node_modules导致超时或误报
CI 流水线里 axe-core 扫描结果必须断言失败
axe-core 返回的是 JSON 结构,不手动检查 violations 数量,它就只是个报告生成器,不会中断构建。
立即学习“前端免费学习笔记(深入)”;
- 在 Puppeteer 脚本中加判断:
if (results.violations.length > 0) throw new Error(`a11y violations: ${results.violations.map(v => v.help).join('; ')}`) - Playwright 中更简洁:
expect(results.violations).toHaveLength(0),失败时自动打印违规项帮助定位 - 不要依赖 Lighthouse CI:它默认不因 a11y 分数低而失败,需额外配
assertions,且启动开销大、不可裁剪规则集 - baseline 对比很重要:把上一版
axe.run()的violations数存下来,CI 中只允许新增 ≤1 条 warning 级问题,critical 级新增直接失败
最容易被忽略的是环境一致性:本地跑 axe 全绿,CI 报一堆 color-contrast 错误,往往是因为 CI 中 CSS 没加载完成、字体未就绪、或 viewport 尺寸不同导致计算偏差——这些不是代码问题,但必须通过等待策略和环境模拟来对齐。


















