戳这里查看上期,上篇梳理了axe和Lighthouse的自动化检测能力与边界,今天将继续深挖~
6. 自动化检测拦不住的无障碍回归
想象一下:开发者看了 WCAG 文档,给某个问题加了正确修复,后来另一个 linter 或者好心的同事,没看过对应最佳实践,觉得第一个开发者写错了,又把 "修复" 给改了。
两个很常见的例子:
• alt="" 其实是装饰性图片的正确写法,明确告诉屏幕阅读器跳过这个元素。但有的 linter 会提示缺少 alt 文本,或者开发者看到空 alt 以为是漏写了,改成 alt="装饰图片"。结果屏幕阅读器会把每个装饰元素都播报 "装饰图片"—— 平白多了一堆噪音。
• 带文字的按钮里,图标加 aria-hidden="true" 是正确的,因为按钮的无障碍名称已经由可见文字提供了。删掉它换成 aria-label="图标",工具能通过,但会干扰无障碍名称计算,还可能覆盖按钮本身的真实标签。
这两种情况里,通过了自动化检测,反而掩盖了回归问题。原本的状态比 "修复后" 更无障碍。
💡 修复方案: 把 alt="" 和 aria-hidden="true" 当成有意为之的配置,不是疏漏。加注释说明意图,避免团队误改: |
7. WCAG 颜色对比度自动化检测的局限
Lighthouse 和 axe 现在已经能检测纯色背景上标准文本的对比度问题了 —— 这确实是进步,也是自动化工具实打实的提升。
但依然存在缺口:
• 图片或渐变上的文字 —— axe-core 可能无法准确报告渐变或图片背景上的对比度问题
• 半透明背景 —— 计算出的颜色可能不准确
• 悬停和聚焦状态 —— 扫描只检测当前状态的元素,聚焦环、悬停样式的对比度不足,只要扫描时没触发对应状态就发现不了
• 深色模式 —— 浅色模式下的扫描,发现不了深色模式的对比度问题,反之亦然
后面我会给几个 Playwright 测试,在扫描前触发悬停、聚焦、深色模式这些状态 —— 补上默认扫描漏掉的对比度问题。
自动化能检测到的对比度问题,用专门的检测工具比等 CI 扫描更可控。
我做的 WCAG 颜色对比度检查工具,可以测试特定颜色对是否符合 AA、AAA 标准,模拟四种色盲下的显示效果,还能生成可直接粘贴的 bug 报告,包含推荐的最接近达标颜色修复方案。
渐变这类更难检测的问题,人工验证渐变上对比度的一个方法,就是分别校验渐变两端的颜色。比如:
在颜色对比度检查工具里输入前景色 #544f4f、背景色 #ffffff,校验通过后,再用背景色 #000000 测一遍。
多段渐变就每个色标都测一遍。每个色标位置文字都达标,整个渐变上的文字就达标。
8. 遗留 HTML 场景下,Lighthouse 的地标建议反而会帮倒忙
Lighthouse 会把缺少地标区域标记为无障碍违规。在现代 HTML5 代码库里,这个建议很直接 —— 加上<main>、<nav>、<header>就行。
但在 HTML5 之前的文档类型里(比如严格版 XHTML、严格版 HTML 4.01),这些元素属于无效标签。
不理解文档类型限制就直接照着建议改,最终写出来的代码既不符合语法规范,表面上又好像满足了无障碍规则。
遗留代码里正确的修复方式,是给<div>元素加上 ARIA 地标角色:
自动化工具是按理想的现代 HTML5 场景来校验的。它们感知不到你的文档类型限制,也区分不了 "缺少地标" 和 "遗留代码库正确实现了 ARIA 地标角色" 的区别。
💡 修复方案: HTML5 之前的代码场景,用 ARIA 地标角色,不用 HTML5 原生地标元素。 HTML5 代码库里就用原生元素 —— 它们自带地标角色语义,不用额外加role属性。 |
9. 表单无障碍:标签、提示、错误信息,自动化工具都会漏
自动化工具能稳定检出缺少<label>、表单字段没有无障碍名称的问题。但它们判断不了标签、说明文字、错误提示到底有没有实际作用。
关联了文本输入框的<label>First name</label>,所有自动化检测都能过。<label>Field 1</label>也能过。工具只看到 "有标签"—— 不会读内容本身。
整个表单体验里,这类缺口到处都是:
• 只有占位符做提示 —— 用户一开始输入,占位符就消失了,根本记不住字段要求。自动化工具不会标记这个问题。
• 错误提示模糊 ——"输入无效" 和 "邮箱格式必须为name@example.com" 都能过检测,但只有一个能帮用户改正。
• 错误提示位置 —— 只出现在页面顶部的错误,虽然满足 WCAG 的错误识别要求,但键盘和屏幕阅读器用户填长表单的时候,根本找不到在哪。
• 错误播报时机 —— 错误是通过aria-live还是aria-describedby播报,屏幕阅读器能不能真的读到,得用真实辅助技术测,不是扫 DOM 就行。
• 必填项标记 —— 红星是视觉约定。没有对应的文本说明或者aria-required="true",屏幕阅读器用户提交失败了才知道这个字段必填。
💡 修复方案: 每个表单都只用键盘和真实屏幕阅读器测一遍。主动触发错误状态 —— 必填字段空着提交、输入错误格式。 然后验证播报的错误有没有说清哪里错了、怎么改。确认占位符之外还有一直显示的可见标签,不是用占位符代替标签。 |
10. 键盘无障碍:动态内容、弹窗、交互组件
自动化工具能验证弹窗有没有role="dialog"、有没有无障碍名称,折叠按钮有没有aria-expanded。但它们做不到像键盘用户那样和组件交互 —— 验证实际导航的时候行为对不对。
这是静态 DOM 扫描的结构性局限。扫描工具只评估加载完成的页面 —— 不会点按钮、开弹窗、按按键。
它能确认弹窗的 ARIA 属性写得对,但用户真打开之后会发生什么,它根本验证不了。
这个缺口刚好是 Playwright 的价值所在:它能模拟真实键盘交互,然后校验结果。
这个领域最常见的问题:
• 弹窗打开后焦点没移过去 —— 弹窗视觉上出来了,但键盘焦点还在后面,键盘用户根本进不去内容
• 弹窗里焦点没锁住 —— 按 Tab 应该只在弹窗里的可聚焦元素间循环;如果焦点跑到后面的页面里,键盘用户根本不知道自己在哪
• 没有 Esc 关闭 —— 键盘用户都习惯按 Esc 关弹窗;只靠关闭按钮的话,得按半天 Tab 才能找到
• 关闭后焦点没回去 —— 弹窗关掉后,焦点应该回到触发它的元素;焦点乱跑的话,键盘用户得从头重新导航
• 展开 / 折叠的键盘触发 —— 只响应鼠标点击的折叠面板,键盘用不了;Enter 和空格都应该能触发切换
• 动态新增内容没播报 —— 交互后出现的内容(搜索结果、实时校验、通知),得有aria-live区域或者明确的焦点管理,屏幕阅读器用户才能知道
💡 修复方案: 每个交互组件都只用键盘测一遍 —— 不用鼠标。用 Enter 开弹窗,Tab 和 Shift+Tab 在里面导航,Esc 关闭,验证焦点回到触发元素。 展开折叠控件 Enter 和空格都要试,确认展开的内容按 Tab 能到达。 |
这些键盘路径都可以用 Playwright 写成自动化用例:

