axe-core必须在真实渲染的DOM上运行,能检测焦点管理、ARIA属性缺失、颜色对比度等动态可访问性问题,而html-validate仅检查静态HTML源码层面的硬性违规,二者互补但不可替代。

直接结论:可访问性达标率不能只看“有没有alt”或“用了
html-validate 能查什么、不能查什么
它检查源码层面的硬性违规,比如 img 缺 alt、input 没被 label 包裹、button 没 type 属性。但以下情况它完全不感知:
- JS 动态插入的
img标签没补alt(比如懒加载后塞进 DOM 的图) -
aria-live区域没正确声明,或更新时没触发屏幕阅读器播报 - 用
div+onclick模拟按钮,却没加tabindex="0"和键盘事件监听 - SSR 渲染中
window调用导致服务端崩溃,进而让整个页面结构缺失
也就是说,html-validate 报 98% 合规,不代表真实用户能顺畅操作。
axe-core 必须在真实 DOM 上跑
axe 不分析字符串,而是注入到已渲染的页面中执行 DOM 遍历。它能发现:
立即学习“前端免费学习笔记(深入)”;
-
document.querySelectorAll('button[role="button"]')中哪些实际不可聚焦(缺少tabindex或未处理Enter/Space) - 焦点管理失效:模态框打开后,Tab 键仍能离开遮罩层
-
aria-hidden="true"错加在带tabindex="0"的元素上 - 颜色对比度不足——这需要真实渲染后的像素计算,静态 HTML 无法判断
注意:axe 在 CI 中应运行在 Puppeteer 或 Playwright 启动的真实浏览器环境里,不是 Node.js 直接解析 HTML 字符串。
模板库自身的可访问性设计缺陷
很多框架模板库(如某些 React/Vue 组件库)把可访问性当“可选增强”,结果埋下三类典型坑:
- 组件内部用
div实现折叠面板,却没暴露aria-expanded和aria-controls属性接口 - 图标按钮默认
alt="",也不允许传入aria-label,开发者只能 hack 外层包裹span - 表单校验错误信息用
div渲染,没绑定aria-describedby到对应input,屏幕阅读器根本读不到
这类问题不会出现在 html-validate 报告里,axe 也只报“缺失 ARIA 关联”,但根源是模板库 API 设计没把可访问性作为必填契约。
真正卡住达标率的,从来不是某张图缺 alt,而是模板库把“可访问性支持”做成 opt-in 而非 default——你得主动写 aria-label、手动加 tabIndex、自己管焦点流。这种设计让达标率永远依赖开发者个体意识,而非系统约束。



















