前端可访问性:自动化测试工具与实践指南
前端可访问性:自动化测试工具与实践指南
前言
各位前端小伙伴,今天咱们来聊聊可访问性的自动化测试。想象一下:
- 你开发了一个功能丰富的网站
- 手动测试时觉得一切正常
- 但发布后发现有很多可访问性问题
- 用户投诉不断
自动化测试可以帮助我们在开发过程中及时发现问题。今天咱们就来学习主流的可访问性测试工具和实践!
自动化测试工具概览
工具对比
| 工具 | 类型 | 集成方式 | 检测能力 |
|---|---|---|---|
| axe-core | JavaScript库 | 代码/CLI | 完整的WCAG检测 |
| Lighthouse | Chrome扩展 | CLI/CI | 综合性能+可访问性 |
| Pa11y | CLI工具 | CLI/CI | 基于axe-core |
| eslint-plugin-jsx-a11y | ESLint插件 | 开发时 | React特定规则 |
| Cypress-axe | Cypress插件 | E2E测试 | 集成到端到端测试 |
axe-core 使用指南
基础使用
// 安装 npm install axe-core // 基本检测 import axe from 'axe-core'; async function runAxeTest() { const results = await axe.run(document, { // 配置选项 runOnly: { type: 'tag', values: ['wcag2a', 'wcag2aa', 'wcag21aa'] } }); // 处理结果 if (results.violations.length > 0) { console.error('发现可访问性问题:', results.violations); // 输出详细信息 results.violations.forEach((violation, index) => { console.log(`\n问题 ${index + 1}: ${violation.help}`); console.log(`影响: ${violation.impact}`); console.log('元素:', violation.nodes.map(n => n.target).join(', ')); }); } else { console.log('可访问性检测通过!'); } return results; }自定义规则
const customRules = [{ id: 'custom-button-rule', description: '自定义按钮规则', help: '按钮必须有明确的文本内容', helpUrl: 'https://example.com/button-accessibility', category: 'custom', severity: 'error', matches: function(node, options, virtualNode) { return node.nodeName === 'BUTTON'; }, test: function(node, options, virtualNode) { const textContent = virtualNode.text || ''; return textContent.trim().length > 0; } }]; // 使用自定义规则运行检测 async function runCustomAxeTest() { const results = await axe.run(document, { rules: { ...axe.getDefaultRules(), 'custom-button-rule': customRules[0] } }); return results; }Lighthouse 集成
CLI使用
# 安装Lighthouse npm install -g lighthouse # 运行检测 lighthouse https://example.com --view # 仅检测可访问性 lighthouse https://example.com --only-categories=accessibility编程式使用
const lighthouse = require('lighthouse'); const chromeLauncher = require('chrome-launcher'); async function runLighthouse(url) { const chrome = await chromeLauncher.launch({ chromeFlags: ['--headless'] }); const options = { logLevel: 'info', output: 'json', onlyCategories: ['accessibility'], port: chrome.port }; const runnerResult = await lighthouse(url, options); const accessibilityScore = runnerResult.lhr.categories.accessibility.score * 100; console.log(`可访问性得分: ${accessibilityScore}分`); // 输出详细报告 runnerResult.lhr.audits.forEach(audit => { if (audit.score === 0) { console.log(`\n失败: ${audit.title}`); console.log(audit.description); } }); await chrome.kill(); return runnerResult; } runLighthouse('https://example.com');ESLint 集成
eslint-plugin-jsx-a11y
# 安装 npm install eslint-plugin-jsx-a11y --save-dev// .eslintrc.js module.exports = { plugins: ['jsx-a11y'], rules: { // 强制img标签有alt属性 'jsx-a11y/alt-text': 'error', // 强制按钮有明确的文本 'jsx-a11y/button-has-type': 'error', // 强制label与表单元素关联 'jsx-a11y/label-has-associated-control': 'error',