HTMLHint 的可访问性规则需显式启用,如 "alt-require": true 和 "input-requires-label": true;axe-core 必须在 Puppeteer 等真实 DOM 环境运行,二者分工明确:HTMLHint 检查源码意图,axe 检测运行时可访问性缺陷。

HTMLHint 的可访问性规则必须显式启用,否则等于没开
很多人装了 HTMLHint 就以为 alt 检查自动生效,结果上线后被 axe 报出一堆缺失 alt 的问题。根本原因是:默认配置里 "alt-require": true 和 "input-requires-label": true 都是关着的。
你得在 .htmlhintrc 里明确写上这两条:
{
"rules": {
"alt-require": true,
"input-requires-label": true
}
}
-
alt-require会拒绝所有没alt属性的<img>,包括src是 SVG 或 data URL 的情况 -
input-requires-label不认aria-label,只认原生<label for="xxx">或包裹结构;<textarea>和<select>同样受约束 - 大小写敏感:
for="MyInput"和id="myinput"不匹配,会被报错
axe-core 必须在真实 DOM 环境运行,静态扫描无效
axe-core 的作用不是看源码,而是看渲染后的 DOM。它能发现 JS 动态插入的 <img> 没补 alt、模态框打开后焦点没锁定、aria-live 区域没声明等运行时缺陷——这些 HTMLHint 根本看不到。
CI 中必须搭配 Puppeteer 启动浏览器环境:
立即学习“前端免费学习笔记(深入)”;
const axe = require('axe-core');
const puppeteer = require('puppeteer');
(async () => {
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('http://localhost:3000');
const results = await page.evaluate(() => axe.run());
console.log(results.violations);
await browser.close();
})();
- 本地开发用
http://localhost:3000,CI 中要等服务真正启动后再跑 axe,不能直接扫文件 - 别用
axe.run(document)在 Node.js 里调,那只是模拟 DOM,不触发真实渲染逻辑 - 部分结果需人工判断(比如某张图是否真为装饰性),CI 脚本里建议设为 warning 级别,不直接阻断构建
CI 中 HTMLHint 失败必须阻断,axe 失败建议标记而非拦截
HTMLHint 查的是源码意图:缺 alt 就是硬伤,不该上线;而 axe 查的是运行时表现:某个 aria-hidden 是否误用了,可能依赖上下文。
-
HTMLHint在 pre-commit 或 lint 阶段运行,加--fail-on-warn参数确保 warning 也退出非零码 -
axe结果里带helpUrl和impact字段,高危项(如color-contrast)可设阈值拦截,低风险项(如duplicate-id)只记录 - GitHub Actions 示例中,
htmlhint步骤失败直接if: always()终止后续,axe步骤失败则只发 Slack 通知
W3C Validator 和 html-validate 不能替代可访问性检查
vnu.jar 或 html-validate 验证的是语法和语义合规性,比如 <h2> 是否嵌套在 <section> 里、<picture> 是否合法。它们不会告诉你“这个按钮没有键盘支持”或“这个图表缺少长描述链接”。
-
vnu.jar认为<img src="logo.svg">是合法 HTML5,哪怕它对屏幕阅读器完全失明 -
html-validate默认不启用img-req-alt规则,需手动开启;即使开了,它也不检查 JS 插入的图片 - 真正难的不是工具报错,而是看到
frame-title-require错误时,你得立刻判断那个<iframe>是嵌第三方客服系统还是地图——前者可忽略,后者必须加title



















