屏幕阅读器兼容
屏幕阅读器是视障用户访问网页的主要工具。了解不同屏幕阅读器的工作原理、对各 HTML 特性的支持差异,以及正确的测试方法,是确保无障碍设计有效落地的关键。本节将介绍主流屏幕阅读器(NVDA、JAWS、VoiceOver)的特点、语义化 HTML 对屏幕阅读器的影响,以及实用的测试方法。
前置知识
阅读本节前,建议先了解:跳过导航链接
主流屏幕阅读器
常见屏幕阅读器一览
| 屏幕阅读器 | 平台 | 价格 | 市场占有率 |
|---|---|---|---|
| NVDA | Windows | 免费开源 | 全球最大 |
| JAWS | Windows | 付费(约 $1000/年) | 美国市场最大 |
| VoiceOver | macOS / iOS | 免费(系统内置) | Mac 用户标配 |
| TalkBack | Android | 免费(系统内置) | Android 用户标配 |
| Narrator | Windows | 免费(系统内置) | 辅助/临时使用 |
屏幕阅读器的工作原理
解析流程
屏幕阅读器通过以下步骤解析页面:
- DOM 解析:获取页面 DOM 树
- Accessibility Tree:浏览器将 DOM 转换为无障碍树
- 语义提取:从无障碍树中提取语义信息
- 播报输出:将语义信息转化为语音或盲文输出
HTML → DOM Tree → Accessibility Tree → 语音/盲文输出模式概述
屏幕阅读器主要有两种浏览模式:
| 模式 | 说明 | 操作方式 |
|---|---|---|
| 浏览模式(虚拟光标) | 自由浏览页面内容 | 方向键、快捷键 |
| 表单模式(焦点模式) | 与表单和交互元素交互 | Tab、Enter、Space |
用户可以在两种模式间切换(通常通过 Tab 键进入表单模式,Escape 键返回浏览模式)。
语义化 HTML 对屏幕阅读器的影响
原生元素 vs 自定义元素
html
<!-- 屏幕阅读器播报:"链接,首页" -->
<a href="/">首页</a>
<!-- 屏幕阅读器播报:"链接,首页"(语义相同) -->
<a href="/" role="link">首页</a>
<!-- 屏幕阅读器播报可能不完整 -->
<div onclick="location.href='/'">首页</div>heading 层级的影响
html
<!-- 屏幕阅读器使用 heading 快速浏览 -->
<!-- 用户可以按 H 键跳到下一个标题 -->
<!-- Shift+H 跳到上一个标题 -->
<h1>网站标题</h1>
<h2>文章标题</h2>
<h3>小节标题</h3>
<h3>另一个小节</h3>
<h2>另一篇文章</h2>
<!-- 屏幕阅读器提供标题导航列表 -->
<!-- 用户可以按 Insert+F6(NVDA)列出所有标题 -->表单元素
html
<!-- 播报:"用户名,编辑框" -->
<label for="name">用户名</label>
<input type="text" id="name" />
<!-- 播报:"编辑框,用户名"(顺序不同,但信息完整) -->
<input type="text" id="name" aria-label="用户名" />
<!-- 播报不完整:缺少标签 -->
<input type="text" placeholder="用户名" />
<!-- 屏幕阅读器可能只播报:"编辑框" -->图片替代文本
html
<!-- 播报:"图片,一个微笑的人" -->
<img src="person.jpg" alt="一个微笑的人" />
<!-- 播报:"图片" 或不播报(装饰性图片) -->
<img src="decoration.png" alt="" role="presentation" />
<!-- 播报:"图片,person-dot-jpg"(不推荐) -->
<img src="person.jpg" />各屏幕阅读器特性
NVDA(NonVisual Desktop Access)
NVDA 是一款免费的 Windows 屏幕阅读器,使用 Python 开发,由 NV Access 维护。
| 特性 | 说明 |
|---|---|
| 快捷键 | Insert+H:帮助;Insert+F7:元素列表;Insert+T:标题导航 |
| 浏览模式 | 支持虚拟光标浏览 |
| 浏览器支持 | 主要使用 Firefox(兼容性最佳),也支持 Chrome/Edge |
| 开发者工具 | NVDA 开发者工具集(用于诊断) |
| 测试方法 | 可免费下载安装进行测试 |
JAWS(Job Access With Speech)
JAWS 是商业屏幕阅读器,功能强大但价格昂贵。
| 特性 | 说明 |
|---|---|
| 快捷键 | Insert+F5:表单列表;Insert+F6:标题列表;Insert+F7:链接列表 |
| 浏览器支持 | 主要使用 Chrome/Edge(FS 2024 后支持更好) |
| 脚本支持 | 支持自定义脚本扩展功能 |
| 测试方法 | 有 40 分钟试用模式;可使用 WebAIM 屏幕阅读器模拟器 |
VoiceOver(macOS / iOS)
VoiceOver 是苹果系统内置的屏幕阅读器。
| 特性 | 说明 |
|---|---|
| 启动方式 | macOS:Command+F5;iOS:三击 Home/电源键 |
| 快捷键 | VO+U: rotor;VO+H:标题导航;VO+Command+H:标题列表 |
| 浏览器支持 | Safari(最佳)、Chrome、Firefox |
| 测试方法 | Mac 用户可以直接启用进行测试 |
测试方法
方法 1:浏览器开发者工具
现代浏览器内置了无障碍检查工具:
html
<!-- Chrome DevTools → Elements → Accessibility 面板 -->
<!-- 可以查看无障碍树、ARIA 属性、计算的角色等 -->html
<!-- Firefox Accessibility Inspector -->
<!-- 工具 → Web 开发者 → 无障碍 -->方法 2:浏览器内置屏幕阅读器
- ChromeVox(Chrome 扩展):Chrome 内置的屏幕阅读器
- VoiceOver(macOS Safari):系统内置,免费使用
方法 3:真实屏幕阅读器测试
| 步骤 | 操作 |
|---|---|
| 1 | 安装屏幕阅读器(NVDA 免费) |
| 2 | 使用 Tab 键从页面顶部开始导航 |
| 3 | 使用 heading 快捷键检查标题结构 |
| 4 | 使用链接列表检查链接描述 |
| 5 | 填写表单,验证标签播报 |
| 6 | 使用虚拟光标浏览页面内容 |
| 7 | 测试自定义组件的交互行为 |
方法 4:自动化测试
html
<!-- 使用 axe-core 自动检测 -->
<script src="https://cdn.jsdelivr.net/npm/axe-core@latest"></script>
<script>
axe.run().then(results => {
console.log('违规数量:', results.violations.length);
results.violations.forEach(v => {
console.log(`[${v.impact}] ${v.description}`);
});
});
</script>实战示例:屏幕阅读器友好的页面
html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>屏幕阅读器友好页面示例</title>
<style>
/* 隐藏但可访问的跳过链接 */
.skip-link {
position: absolute;
top: -100%;
left: 0;
padding: 0.5rem 1rem;
background: #0066cc;
color: white;
z-index: 100;
}
.skip-link:focus { top: 0; }
</style>
</head>
<body>
<a href="#main" class="skip-link">跳到主要内容</a>
<header>
<h1>产品详情</h1>
<nav aria-label="面包屑">
<ol>
<li><a href="/">首页</a></li>
<li><a href="/products">产品</a></li>
<li aria-current="page">无线耳机</li>
</ol>
</nav>
</header>
<main id="main">
<section aria-labelledby="product-name">
<!-- 图片有描述性 alt -->
<img src="headphones.jpg" alt="黑色无线蓝牙入耳式耳机产品图" />
<!-- heading 提供标题 -->
<h2 id="product-name">高端无线蓝牙耳机 Pro</h2>
<!-- 语义化价格信息 -->
<p>
<del>¥499.00</del>
<strong>¥299.00</strong>
<span aria-label="六折优惠">6折</span>
</p>
<!-- 表单有完整的标签 -->
<form>
<fieldset>
<legend>选择颜色</legend>
<label>
<input type="radio" name="color" value="black" checked />
黑色
</label>
<label>
<input type="radio" name="color" value="white" />
白色
</label>
</fieldset>
<div>
<label for="qty">数量</label>
<input type="number" id="qty" min="1" max="10" value="1"
aria-describedby="qty-hint" />
<span id="qty-hint">最多购买 10 件</span>
</div>
<button type="submit">加入购物车</button>
</form>
</section>
</main>
<footer>
<p>版权所有 2024</p>
</footer>
</body>
</html>注意事项
- 不同屏幕阅读器行为不同:同一个页面在不同屏幕阅读器中可能有不同的播报方式
- 测试真实的交互流程:不只是"能不能播报",还要测试"用户能否完成任务"
- 关注浏览模式:屏幕阅读器在浏览模式和表单模式下的行为可能不同
- 考虑阅读速度:冗长的文本会使屏幕阅读器体验变差
- 动态内容:确保 Live Region 在各屏幕阅读器中都能正确触发
最佳实践
- 优先使用语义化 HTML 元素,减少对 ARIA 的依赖
- 为所有交互元素提供清晰的标签和描述
- 维护正确的 heading 层级(h1→h2→h3,不跳级)
- 使用 NVDA + Firefox 或 ChromeVox 进行基础测试
- 让真实屏幕阅读器用户参与测试
- 使用浏览器的 Accessibility Inspector 作为日常开发辅助工具
- 将 axe-core 集成到 CI 流程中作为自动化检查
下一节
继续学习:色彩对比度