axe-core是唯一能卡住重构红线的工具,因其完整规则集可校验wcag规范如color-contrast、heading-order、label缺失等,而page.accessibility.snapshot()仅返回基础语义树无法覆盖。

组件库重构时,可访问性退化几乎必然发生——不是靠人眼扫一遍就能发现的,必须用自动化回归测试卡住。手动检查漏掉的焦点顺序、ARIA属性错位、表单集成失效等问题,上线后才会暴露。
为什么 axe-core 是唯一能卡住重构红线的工具
别用 page.accessibility.snapshot() 做断言:它只返回基础语义树,不校验 WCAG 规则,比如 color-contrast、heading-order、label 缺失等关键问题全被放过。真正要守住的底线是 axe-core 的完整规则集。
- 必须在 Playwright 测试中注入 axe-core 脚本:
await page.addScriptTag({ path: require.resolve('axe-core') }) - 执行前加等待 hydration 完成:
await page.waitForFunction(() => document.querySelector('#root')?.children.length > 0) - 字体未加载完成会导致
color-contrast误报,补上:await page.waitForFunction(() => document.fonts.check('1em "Inter"')) - CI 中失败时,直接打印
results.violations.map(v => v.help),比截图定位快十倍
自定义元素重构后,表单集成必须重测
x-toggle 或 my-button 重构后,即使视觉和功能都正常,也可能彻底失去表单能力——因为 formAssociated = true、Shadow DOM 内真实 input[type="checkbox"] 的桥接、attributeChangedCallback 中对字符串 "true"/null 的正确转换,三者缺一不可。
- 验证是否进
form.elements:await page.evaluate(() => document.querySelector('form').elements.namedItem('toggle-name') !== undefined) - 检查
disabled是否生效:await expect(page.getByRole('checkbox')).toBeDisabled()(不能只看属性) -
attributeChangedCallback里写input.checked = newValue !== null,别用!!newValue——disabled="false"是合法字符串,但语义不该禁用
步骤向导类组件的焦点流必须录制为快照
重构后,aria-current="step" 可能还在,但键盘 Tab 到下一步时焦点却落在空白处——这是因为焦点管理逻辑被覆盖或未同步更新。纯靠人工 Tab 测试太慢,且易遗漏反向路径。
- 用 Playwright 录制完整焦点流:
await page.keyboard.press('Tab')× N,每步记录document.activeElement的outerHTML和aria-current状态 - 把每一步的聚焦节点序列存为 JSON 快照,每次重构后比对数组长度和每个节点的
tagName+role+aria-label - 特别注意模态框打开后首次
.focus()是否静默失败:必须由用户手势触发(如点击按钮),否则 Safari/Chrome 都会拒绝
重构中最容易被忽略的,是滚动容器自身没设 tabindex="0" 导致焦点“消失”——它根本不在 Tab 流里,但开发者以为只是样式问题;还有 inert 属性拦截了整个区域,却没意识到它会切断所有键盘可达性路径。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











