各位观众老爷们,晚上好!我是你们的 JavaScript 导师,今天咱们来聊点实在的——JavaScript 可访问性测试,也就是如何让我们的 Web 应用对所有人,包括那些使用辅助技术的用户,都友好得像邻家大妈。
咱们先来搞清楚,为啥要搞这个可访问性?难道只是为了显得我们程序员素质高?当然不是!
为啥要关心可访问性 (Accessibility)?
- 法律法规: 在很多国家,网站必须满足一定的可访问性标准,比如美国的 ADA、欧洲的 EN 301 549 等。不遵守?等着律师函吧!
- 用户体验: 可访问性不仅仅是为残疾人服务的,良好的可访问性实践能提升所有用户的体验,比如更好的键盘导航、更清晰的文本等等。
- 商业价值: 别忘了,残疾人群体也是潜在客户!忽略他们,就等于拱手把钱送给竞争对手。
- 道德责任: 作为程序员,我们有责任构建一个包容的互联网,让所有人都能平等地获取信息和服务。
可访问性测试工具:我们的兵器库
就像打仗需要枪炮一样,可访问性测试也需要各种工具。下面介绍几个常用的:
-
Lighthouse (Chrome DevTools): 这是 Chrome 浏览器自带的工具,非常方便。它可以评估网页的性能、可访问性、SEO 等,并给出改进建议。
-
用法: 打开 Chrome DevTools,选择 "Lighthouse" 选项卡,选择 "Accessibility",点击 "Generate report"。
-
优点: 简单易用,集成在浏览器中。
-
缺点: 只能检测单个页面,不能进行自动化测试。
-
-
axe-core: 这是一个强大的可访问性测试引擎,可以集成到各种自动化测试框架中。
-
用法:
-
安装:
npm install axe-core
-
代码示例 (Jest):
const axe = require('axe-core'); describe('Accessibility tests', () => { it('should pass accessibility tests', async () => { document.body.innerHTML = ` <button aria-label="Close">X</button> <img src="logo.png" alt="Company Logo"> <input type="text" id="name" aria-describedby="name-instructions"> <div id="name-instructions">Enter your name here.</div> `; // 这里插入你的 HTML const results = await axe.run(); expect(results.violations).toEqual([]); // 没有违规 if (results.violations.length > 0) { console.log(results.violations); } }); });
-
-
优点: 可靠性高,可定制性强,可以进行自动化测试。
-
缺点: 需要编写测试代码。
-
-
WAVE (Web Accessibility Evaluation Tool): 这是一个在线工具和浏览器插件,可以快速评估网页的可访问性。
-
用法: 访问 https://wave.webaim.org/,输入网址,或者安装浏览器插件。
-
优点: 简单直观,可以快速发现问题。
-
缺点: 不能进行自动化测试。
-
-
Accessibility Insights: 微软出品,必属精品。提供 Web 和 Windows 应用的可访问性测试。
- 用法: 浏览器插件,直接分析页面。
- 优点: 详细的报告,支持多种平台。
- 缺点: 需要安装插件。
-
Pa11y: Pa11y 是一个命令行工具,可以对网站进行自动化可访问性测试。它基于 PhantomJS 或 Chrome Headless。
- 用法:
- 安装:
npm install -g pa11y
- 运行:
pa11y http://example.com
- 安装:
- 优点: 自动化测试,可以集成到 CI/CD 流程中。
- 缺点: 需要配置和命令行操作。
- 用法:
可访问性最佳实践:葵花宝典
光有工具还不够,还得掌握一些武功秘籍,才能真正提升 Web 应用的可访问性。
-
语义化 HTML: 使用正确的 HTML 标签,让浏览器和辅助技术能够理解网页的结构和内容。
- 要点: 使用
<header>
,<nav>
,<main>
,<article>
,<aside>
,<footer>
等语义化标签。 - 反面教材: 滥用
<div>
和<span>
。
<header> <h1>My Awesome Website</h1> <nav> <ul> <li><a href="#">Home</a></li> <li><a href="#">About</a></li> <li><a href="#">Contact</a></li> </ul> </nav> </header> <main> <article> <h2>Article Title</h2> <p>Article content...</p> </article> </main> <footer> <p>© 2023 My Awesome Website</p> </footer>
- 要点: 使用
-
替代文本 (Alt Text): 为所有图片添加
alt
属性,描述图片的内容。- 要点:
alt
属性应该简洁明了,描述图片的功能和用途。如果图片只是装饰性的,可以设置alt=""
。 - 反面教材: 缺少
alt
属性,或者alt
属性内容无关。
<img src="logo.png" alt="Company Logo"> // 好 <img src="decorative-image.png" alt=""> // 好,装饰性图片 <img src="logo.png" alt="image"> // 差
- 要点:
-
标签 (Labels): 为所有表单元素添加标签,让用户知道每个输入框的用途。
- 要点: 使用
<label>
标签,并使用for
属性将其与对应的表单元素关联。 - 反面教材: 没有标签,或者标签与表单元素没有关联。
<label for="name">Name:</label> <input type="text" id="name" name="name"> <!-- 或者 --> <label> Name: <input type="text" name="name"> </label>
- 要点: 使用
-
颜色对比度: 确保文本和背景颜色之间有足够的对比度,让用户能够清晰地阅读文本。
- 要点: 使用颜色对比度检查工具,比如 https://webaim.org/resources/contrastchecker/,确保对比度符合 WCAG 标准。
- 反面教材: 浅色文本在浅色背景上,或者深色文本在深色背景上。
-
键盘可访问性: 确保所有交互元素都可以通过键盘操作。
- 要点: 使用
tab
键进行导航,使用enter
键或space
键激活元素。 - 反面教材: 只能通过鼠标操作的元素。
// JavaScript 示例:处理键盘事件 document.addEventListener('keydown', (event) => { if (event.key === 'Enter' && document.activeElement.classList.contains('my-button')) { // 模拟点击事件 document.activeElement.click(); } });
- 要点: 使用
-
焦点指示器: 当用户使用键盘导航时,清晰地显示当前聚焦的元素。
- 要点: 使用 CSS 的
:focus
伪类,自定义焦点指示器的样式。 - 反面教材: 隐藏默认的焦点指示器,或者使用不明显的样式。
/* CSS 示例:自定义焦点指示器 */ :focus { outline: 2px solid blue; outline-offset: 2px; }
- 要点: 使用 CSS 的
-
ARIA 属性: 使用 ARIA 属性增强 HTML 的语义,为辅助技术提供更多信息。
- 要点: ARIA 属性应该谨慎使用,只在 HTML 无法提供足够语义的情况下才使用。
- 常用 ARIA 属性:
aria-label
,aria-labelledby
,aria-describedby
,aria-hidden
,role
,aria-live
. - 反面教材: 滥用 ARIA 属性,或者使用错误的 ARIA 属性。
<button aria-label="Close">X</button> // 为按钮添加标签 <div role="alert" aria-live="assertive"> // 声明一个警告区域 Error: Invalid input. </div> <div id="instructions">Enter your name here.</div> <input type="text" aria-describedby="instructions"> // input 的描述
-
动态内容更新: 当网页内容动态更新时,通知辅助技术。
- 要点: 使用
aria-live
属性,声明一个动态更新的区域。 aria-live
属性的值:off
: 默认值,不通知辅助技术。polite
: 辅助技术会在空闲时通知用户。assertive
: 辅助技术会立即通知用户,可能会打断用户的操作。
<div aria-live="polite"> The message has been updated: <span id="message">Initial message</span> </div> <script> // JavaScript 示例:更新消息 setTimeout(() => { document.getElementById('message').textContent = 'New message!'; }, 3000); </script>
- 要点: 使用
-
表单错误处理: 当表单验证失败时,清晰地显示错误信息,并引导用户修改错误。
- 要点: 使用
aria-invalid
属性标记无效的表单元素,并使用aria-describedby
属性关联错误信息。 - 反面教材: 错误信息不清晰,或者没有与表单元素关联。
<label for="email">Email:</label> <input type="email" id="email" aria-invalid="true" aria-describedby="email-error"> <div id="email-error">Invalid email address.</div>
- 要点: 使用
-
测试!测试!测试! 定期进行可访问性测试,确保 Web 应用始终符合可访问性标准。
- 要点: 使用自动化测试工具,比如 axe-core,进行持续集成测试。
- 手动测试: 使用屏幕阅读器,比如 NVDA 或 VoiceOver,模拟残疾用户的体验。
代码示例:综合运用
下面是一个简单的例子,演示如何综合运用上述最佳实践:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Accessible Form</title>
<style>
:focus {
outline: 2px solid blue;
outline-offset: 2px;
}
.error {
color: red;
}
</style>
</head>
<body>
<header>
<h1>Contact Us</h1>
</header>
<main>
<form>
<label for="name">Name:</label>
<input type="text" id="name" name="name" required aria-describedby="name-instructions">
<div id="name-instructions">Please enter your full name.</div>
<label for="email">Email:</label>
<input type="email" id="email" name="email" required aria-invalid="false" aria-describedby="email-error">
<div id="email-error" class="error" role="alert" aria-live="polite"></div>
<label for="message">Message:</label>
<textarea id="message" name="message" rows="5" required></textarea>
<button type="submit">Submit</button>
</form>
</main>
<footer>
<p>© 2023 My Awesome Website</p>
</footer>
<script>
const form = document.querySelector('form');
const emailInput = document.getElementById('email');
const emailError = document.getElementById('email-error');
form.addEventListener('submit', (event) => {
if (!emailInput.checkValidity()) {
event.preventDefault();
emailInput.setAttribute('aria-invalid', 'true');
emailError.textContent = 'Please enter a valid email address.';
} else {
emailInput.setAttribute('aria-invalid', 'false');
emailError.textContent = '';
}
});
</script>
</body>
</html>
一些额外的注意事项
- 屏幕阅读器测试: 真正了解可访问性的最好方法是亲自使用屏幕阅读器。NVDA(免费,Windows)和 VoiceOver(macOS 自带)都是不错的选择。
- 键盘导航测试: 确保你能只用键盘完成所有操作。尝试用
Tab
键导航,用Enter
键或Space
键激活元素。 - 持续学习: 可访问性是一个不断发展的领域,定期关注最新的标准和最佳实践。WCAG (Web Content Accessibility Guidelines) 是最重要的参考资料。
表格总结:
类别 | 工具/技术 | 描述 |
---|---|---|
测试工具 | Lighthouse | Chrome DevTools 内置,用于评估网页可访问性,提供改进建议。 |
axe-core | 可集成到自动化测试框架中的可访问性测试引擎,用于进行自动化测试。 | |
WAVE | 在线工具和浏览器插件,用于快速评估网页的可访问性。 | |
Accessibility Insights | 微软出品,提供 Web 和 Windows 应用的可访问性测试,报告详细,支持多种平台。 | |
Pa11y | 命令行工具,用于自动化可访问性测试,可以集成到 CI/CD 流程中。 | |
HTML 语义化 | 语义化标签 | 使用 <header> , <nav> , <main> , <article> , <aside> , <footer> 等标签,描述网页结构。 |
图像 | alt 属性 | 为 <img> 标签添加 alt 属性,描述图片的内容,用于屏幕阅读器。 |
表单 | label 标签 | 使用 <label> 标签为表单元素添加标签,并使用 for 属性关联。 |
对比度 | 颜色对比度 | 确保文本和背景颜色之间有足够的对比度,符合 WCAG 标准。 |
键盘导航 | Tab 键 | 确保所有交互元素都可以通过键盘的 Tab 键进行导航,并使用 Enter 或 Space 键激活。 |
焦点 | :focus 伪类 | 使用 CSS 的 :focus 伪类,自定义焦点指示器的样式,清晰地显示当前聚焦的元素。 |
ARIA | ARIA 属性 | 使用 ARIA 属性增强 HTML 的语义,为辅助技术提供更多信息,如 aria-label , aria-labelledby , aria-describedby , aria-hidden , role , aria-live 。 |
动态内容 | aria-live | 使用 aria-live 属性声明一个动态更新的区域,通知辅助技术。 |
错误处理 | aria-invalid | 使用 aria-invalid 属性标记无效的表单元素,并使用 aria-describedby 属性关联错误信息。 |
测试 | 屏幕阅读器 | 使用屏幕阅读器(如 NVDA 或 VoiceOver)进行手动测试,模拟残疾用户的体验。 |
总结:
可访问性测试不是一次性的任务,而是一个持续的过程。我们需要将可访问性融入到开发的每一个环节,从设计到编码,再到测试。记住,构建一个可访问的 Web 应用,不仅仅是遵守法律法规,更是对所有用户的尊重和关怀。希望大家都能成为可访问性领域的武林高手,构建更加包容和友好的互联网!
好了,今天的讲座就到这里,大家有什么问题可以提问,没有问题的话… 散会!