【前端无障碍】无障碍测试确保你的应用对所有人友好前言大家好我是cannonmonster01今天咱们来聊聊无障碍测试这个话题。无障碍设计不仅仅是开发阶段的事情测试阶段同样重要。只有通过全面的测试才能确保你的应用对所有用户都友好。为什么需要无障碍测试合规性许多国家和地区都有无障碍法规要求用户体验确保所有用户都能正常使用你的应用品牌形象展示企业的社会责任市场扩展覆盖更多用户群体测试类型1. 自动化测试使用工具自动检测常见的无障碍问题import axe from axe-core; // 测试整个页面 axe.run().then(results { console.log(无障碍问题:, results.violations); }); // 测试特定元素 axe.run(#main).then(results { console.log(主要内容区域的问题:, results.violations); });2. 手动测试由测试人员手动检查无障碍功能// 手动测试清单 const accessibilityChecklist [ 所有图片都有alt文本, 所有表单元素都有标签, 所有交互元素都可通过键盘访问, 焦点顺序逻辑正确, 颜色对比度符合要求, 跳过链接正常工作, 模态框能正确管理焦点 ];3. 用户测试邀请真实用户进行测试// 用户测试反馈收集 const userFeedback { screenReader: [], keyboardOnly: [], lowVision: [], cognitive: [] };测试工具1. axe-coreimport axe from axe-core; describe(无障碍测试, () { test(首页应该没有严重的无障碍问题, async () { const results await axe.run(); // 确保没有严重违规 const criticalViolations results.violations.filter( v v.impact critical ); expect(criticalViolations).toEqual([]); }); });2. Lighthouse# 使用Lighthouse测试无障碍 lighthouse https://example.com --view --categoriesaccessibility # 生成报告 lighthouse https://example.com --outputhtml --output-pathreport.html3. WAVEWAVE是一个浏览器扩展可以直接在页面上标注无障碍问题。4. 屏幕阅读器工具平台说明NVDAWindows免费屏幕阅读器VoiceOvermacOS/iOS苹果内置屏幕阅读器JAWSWindows商业屏幕阅读器TalkBackAndroidGoogle内置屏幕阅读器自动化测试集成集成到CI/CD# .github/workflows/accessibility.yml name: 无障碍测试 on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - name: 设置Node.js uses: actions/setup-nodev3 with: node-version: 18 - name: 安装依赖 run: npm install - name: 运行无障碍测试 run: npm run test:accessibility在Playwright中集成import { test, expect } from playwright/test; import AxeBuilder from axe-core/playwright; test(页面应该无障碍, async ({ page }) { await page.goto(/); const accessibilityResults await new AxeBuilder({ page }).analyze(); expect(accessibilityResults.violations).toEqual([]); });手动测试技巧键盘导航测试// 键盘导航测试步骤 const keyboardTestSteps [ 使用Tab键导航所有可聚焦元素, 使用Enter键激活按钮和链接, 使用空格键激活按钮, 使用Escape键关闭模态框, 验证焦点顺序逻辑正确, 验证焦点样式可见 ];屏幕阅读器测试// 屏幕阅读器测试步骤 const screenReaderSteps [ 页面标题能被正确读取, 所有链接文本清晰, 所有按钮有明确标签, 表单有适当描述, 动态内容有实时更新, 模态框能正确管理焦点 ];常见无障碍问题1. 缺少替代文本!-- 不好 -- img srclogo.png !-- 好 -- img srclogo.png alt公司Logo2. 缺少表单标签!-- 不好 -- input typetext placeholder用户名 !-- 好 -- label forusername用户名/label input idusername typetext3. 键盘不可访问!-- 不好 -- div onclickhandleClick按钮/div !-- 好 -- button onclickhandleClick按钮/button4. 颜色对比度不足/* 不好对比度不够 */ .text { color: #666; background: #f0f0f0; } /* 好对比度至少4.5:1 */ .text { color: #333; background: #fff; }测试策略分层测试// 测试层次 const testLayers { unit: 组件级无障碍测试, integration: 集成级无障碍测试, e2e: 端到端无障碍测试, manual: 人工无障碍测试, user: 用户无障碍测试 };优先级测试// 按优先级排序的测试项 const priorityTests [ { priority: critical, test: 所有交互元素必须可键盘访问 }, { priority: critical, test: 所有图片必须有alt文本 }, { priority: high, test: 颜色对比度符合要求 }, { priority: high, test: 表单元素必须有标签 }, { priority: medium, test: 页面标题必须清晰 }, { priority: medium, test: 链接文本必须描述目标 }, { priority: low, test: 提供跳过导航链接 } ];实战案例测试无障碍表单import { test, expect } from playwright/test; test(表单应该无障碍, async ({ page }) { await page.goto(/form); // 测试标签关联 const usernameInput await page.$(#username); const label await page.$(label[forusername]); expect(label).not.toBeNull(); // 测试ARIA属性 const emailInput await page.$(#email); const ariaDescribedBy await emailInput.getAttribute(aria-describedby); expect(ariaDescribedBy).toBeTruthy(); // 测试键盘访问 await page.focus(#username); await page.keyboard.press(Tab); const focusedElement await page.evaluate(() document.activeElement.id); expect(focusedElement).toBe(email); });测试模态框test(模态框应该无障碍, async ({ page }) { await page.goto(/modal); // 打开模态框 await page.click(#open-modal); // 测试ARIA属性 const modal await page.$([roledialog]); expect(modal).not.toBeNull(); const ariaModal await modal.getAttribute(aria-modal); expect(ariaModal).toBe(true); // 测试焦点管理 const focusedElement await page.evaluate(() document.activeElement.getAttribute(role)); expect(focusedElement).toBe(dialog); // 关闭模态框 await page.keyboard.press(Escape); // 测试焦点返回 const returnFocus await page.evaluate(() document.activeElement.id); expect(returnFocus).toBe(open-modal); });测试报告生成测试报告import axe from axe-core; async function generateAccessibilityReport() { const results await axe.run(); const report { summary: { passes: results.passes.length, violations: results.violations.length, incomplete: results.incomplete.length }, violations: results.violations.map(v ({ id: v.id, severity: v.impact, description: v.description, elements: v.nodes.map(n n.target) })) }; return report; }报告示例{ summary: { passes: 45, violations: 3, incomplete: 0 }, violations: [ { id: image-alt, severity: critical, description: 图片缺少替代文本, elements: [img[src\logo.png\]] } ] }常见误区误区1自动化测试足够了事实自动化测试只能发现约30%的无障碍问题。误区2无障碍测试只需要做一次事实无障碍测试应该持续进行每次代码变更都需要测试。误区3无障碍会影响开发进度事实提前考虑无障碍可以避免后期的大量返工。总结无障碍测试是确保应用对所有用户友好的关键环节。通过今天的学习相信你已经掌握了无障碍测试的重要性自动化测试工具和方法手动测试技巧测试策略和最佳实践常见问题和解决方案让我们一起创建更包容的Web体验
【前端无障碍】无障碍测试:确保你的应用对所有人友好
【前端无障碍】无障碍测试确保你的应用对所有人友好前言大家好我是cannonmonster01今天咱们来聊聊无障碍测试这个话题。无障碍设计不仅仅是开发阶段的事情测试阶段同样重要。只有通过全面的测试才能确保你的应用对所有用户都友好。为什么需要无障碍测试合规性许多国家和地区都有无障碍法规要求用户体验确保所有用户都能正常使用你的应用品牌形象展示企业的社会责任市场扩展覆盖更多用户群体测试类型1. 自动化测试使用工具自动检测常见的无障碍问题import axe from axe-core; // 测试整个页面 axe.run().then(results { console.log(无障碍问题:, results.violations); }); // 测试特定元素 axe.run(#main).then(results { console.log(主要内容区域的问题:, results.violations); });2. 手动测试由测试人员手动检查无障碍功能// 手动测试清单 const accessibilityChecklist [ 所有图片都有alt文本, 所有表单元素都有标签, 所有交互元素都可通过键盘访问, 焦点顺序逻辑正确, 颜色对比度符合要求, 跳过链接正常工作, 模态框能正确管理焦点 ];3. 用户测试邀请真实用户进行测试// 用户测试反馈收集 const userFeedback { screenReader: [], keyboardOnly: [], lowVision: [], cognitive: [] };测试工具1. axe-coreimport axe from axe-core; describe(无障碍测试, () { test(首页应该没有严重的无障碍问题, async () { const results await axe.run(); // 确保没有严重违规 const criticalViolations results.violations.filter( v v.impact critical ); expect(criticalViolations).toEqual([]); }); });2. Lighthouse# 使用Lighthouse测试无障碍 lighthouse https://example.com --view --categoriesaccessibility # 生成报告 lighthouse https://example.com --outputhtml --output-pathreport.html3. WAVEWAVE是一个浏览器扩展可以直接在页面上标注无障碍问题。4. 屏幕阅读器工具平台说明NVDAWindows免费屏幕阅读器VoiceOvermacOS/iOS苹果内置屏幕阅读器JAWSWindows商业屏幕阅读器TalkBackAndroidGoogle内置屏幕阅读器自动化测试集成集成到CI/CD# .github/workflows/accessibility.yml name: 无障碍测试 on: push: branches: [main] pull_request: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkoutv3 - name: 设置Node.js uses: actions/setup-nodev3 with: node-version: 18 - name: 安装依赖 run: npm install - name: 运行无障碍测试 run: npm run test:accessibility在Playwright中集成import { test, expect } from playwright/test; import AxeBuilder from axe-core/playwright; test(页面应该无障碍, async ({ page }) { await page.goto(/); const accessibilityResults await new AxeBuilder({ page }).analyze(); expect(accessibilityResults.violations).toEqual([]); });手动测试技巧键盘导航测试// 键盘导航测试步骤 const keyboardTestSteps [ 使用Tab键导航所有可聚焦元素, 使用Enter键激活按钮和链接, 使用空格键激活按钮, 使用Escape键关闭模态框, 验证焦点顺序逻辑正确, 验证焦点样式可见 ];屏幕阅读器测试// 屏幕阅读器测试步骤 const screenReaderSteps [ 页面标题能被正确读取, 所有链接文本清晰, 所有按钮有明确标签, 表单有适当描述, 动态内容有实时更新, 模态框能正确管理焦点 ];常见无障碍问题1. 缺少替代文本!-- 不好 -- img srclogo.png !-- 好 -- img srclogo.png alt公司Logo2. 缺少表单标签!-- 不好 -- input typetext placeholder用户名 !-- 好 -- label forusername用户名/label input idusername typetext3. 键盘不可访问!-- 不好 -- div onclickhandleClick按钮/div !-- 好 -- button onclickhandleClick按钮/button4. 颜色对比度不足/* 不好对比度不够 */ .text { color: #666; background: #f0f0f0; } /* 好对比度至少4.5:1 */ .text { color: #333; background: #fff; }测试策略分层测试// 测试层次 const testLayers { unit: 组件级无障碍测试, integration: 集成级无障碍测试, e2e: 端到端无障碍测试, manual: 人工无障碍测试, user: 用户无障碍测试 };优先级测试// 按优先级排序的测试项 const priorityTests [ { priority: critical, test: 所有交互元素必须可键盘访问 }, { priority: critical, test: 所有图片必须有alt文本 }, { priority: high, test: 颜色对比度符合要求 }, { priority: high, test: 表单元素必须有标签 }, { priority: medium, test: 页面标题必须清晰 }, { priority: medium, test: 链接文本必须描述目标 }, { priority: low, test: 提供跳过导航链接 } ];实战案例测试无障碍表单import { test, expect } from playwright/test; test(表单应该无障碍, async ({ page }) { await page.goto(/form); // 测试标签关联 const usernameInput await page.$(#username); const label await page.$(label[forusername]); expect(label).not.toBeNull(); // 测试ARIA属性 const emailInput await page.$(#email); const ariaDescribedBy await emailInput.getAttribute(aria-describedby); expect(ariaDescribedBy).toBeTruthy(); // 测试键盘访问 await page.focus(#username); await page.keyboard.press(Tab); const focusedElement await page.evaluate(() document.activeElement.id); expect(focusedElement).toBe(email); });测试模态框test(模态框应该无障碍, async ({ page }) { await page.goto(/modal); // 打开模态框 await page.click(#open-modal); // 测试ARIA属性 const modal await page.$([roledialog]); expect(modal).not.toBeNull(); const ariaModal await modal.getAttribute(aria-modal); expect(ariaModal).toBe(true); // 测试焦点管理 const focusedElement await page.evaluate(() document.activeElement.getAttribute(role)); expect(focusedElement).toBe(dialog); // 关闭模态框 await page.keyboard.press(Escape); // 测试焦点返回 const returnFocus await page.evaluate(() document.activeElement.id); expect(returnFocus).toBe(open-modal); });测试报告生成测试报告import axe from axe-core; async function generateAccessibilityReport() { const results await axe.run(); const report { summary: { passes: results.passes.length, violations: results.violations.length, incomplete: results.incomplete.length }, violations: results.violations.map(v ({ id: v.id, severity: v.impact, description: v.description, elements: v.nodes.map(n n.target) })) }; return report; }报告示例{ summary: { passes: 45, violations: 3, incomplete: 0 }, violations: [ { id: image-alt, severity: critical, description: 图片缺少替代文本, elements: [img[src\logo.png\]] } ] }常见误区误区1自动化测试足够了事实自动化测试只能发现约30%的无障碍问题。误区2无障碍测试只需要做一次事实无障碍测试应该持续进行每次代码变更都需要测试。误区3无障碍会影响开发进度事实提前考虑无障碍可以避免后期的大量返工。总结无障碍测试是确保应用对所有用户友好的关键环节。通过今天的学习相信你已经掌握了无障碍测试的重要性自动化测试工具和方法手动测试技巧测试策略和最佳实践常见问题和解决方案让我们一起创建更包容的Web体验