无障碍访问
本教程共 42 篇 · 第 34 篇 · 更新于 2026-07-30 · 约 6 分钟阅读
34. 无障碍访问
本节目标:理解无障碍访问的重要性,掌握 Next.js 内置的 a11y 特性和最佳实践,让所有用户都能使用你的应用。
什么是无障碍访问
无障碍访问(Accessibility,简称 a11y)是指让应用对所有用户都可访问,包括使用屏幕阅读器的视障用户、只能用键盘操作的运动障碍用户、色觉异常的用户等。
Next.js 团队致力于让框架默认就具备良好的无障碍支持。
路由切换通知
页面切换时,屏幕阅读器需要知道页面已经变化。Next.js 默认内置了路由切换通知机制。
自动通知
对于传统的页面跳转(用 <a href>),屏幕阅读器会自动朗读页面标题。
对于 Next.js 的客户端路由(用 <Link> 组件),框架内置了一个路由通知器(Route Announcer)。它会按以下顺序查找要朗读的内容:
document.title- 页面中的
<h1>元素 - URL 路径名
最佳实践:确保每个页面都有唯一且描述性的标题。这是提升无障碍体验最简单有效的方式。
ESLint 无障碍检查
Next.js 内置了 eslint-plugin-jsx-a11y 插件,能在开发阶段捕获常见的无障碍问题。
它检查的内容包括:
aria-props:ARIA 属性的拼写是否正确aria-proptypes:ARIA 属性的值是否合法aria-unsupported-elements:在不支持的元素上用了 ARIArole-has-required-aria-props:角色是否包含必需的 ARIA 属性role-supports-aria-props:角色是否支持对应的 ARIA 属性
比如忘记给图片加 alt 属性,ESLint 就会提示你。
键盘导航
很多用户不用鼠标,只靠键盘操作。确保你的应用能通过 Tab 键访问所有交互元素。
焦点管理
// 用 tabIndex 控制焦点顺序
<button tabIndex={0}>可聚焦按钮</button>
// 避免用 tabIndex > 0,会打乱自然顺序
<div tabIndex={1}>不推荐</div>
自定义组件的键盘支持
自定义下拉菜单、模态框等组件需要手动实现键盘交互:
'use client'
export function Dropdown({ items }) {
const handleKeyDown = (e: React.KeyboardEvent) => {
switch (e.key) {
case 'Escape':
// ESC 关闭下拉菜单
closeDropdown()
break
case 'ArrowDown':
// 向下箭头移动焦点
moveFocus(1)
break
case 'ArrowUp':
// 向上箭头移动焦点
moveFocus(-1)
break
}
}
return (
<ul onKeyDown={handleKeyDown} role="listbox">
{items.map(item => (
<li key={item.id} role="option" tabIndex={0}>
{item.label}
</li>
))}
</ul>
)
}
ARIA 属性
ARIA(Accessible Rich Internet Applications)是一组 HTML 属性,用来增强组件的无障碍信息。
常用 ARIA 属性
| 属性 | 用途 |
|---|---|
role | 定义元素角色(如 button、navigation、alert) |
aria-label | 提供元素的文本描述 |
aria-labelledby | 关联另一个元素作为标签 |
aria-expanded | 指示展开/折叠状态 |
aria-hidden | 对屏幕阅读器隐藏元素 |
aria-live | 声明动态内容区域 |
示例
// 自定义按钮
<div
role="button"
tabIndex={0}
aria-label="关闭对话框"
onClick={onClose}
onKeyDown={e => e.key === 'Enter' && onClose()}
>
✕
</div>
// 导航区域
<nav aria-label="主导航">
<Link href="/">首页</Link>
<Link href="/about">关于</Link>
</nav>
// 动态内容通知
<div aria-live="polite">
{notification && <p>{notification}</p>}
</div>
屏幕阅读器测试
开发完成后,用实际屏幕阅读器测试你的应用:
- Windows:NVDA(免费)或 JAWS
- macOS/iOS:VoiceOver(内置)
- Android:TalkBack(内置)
测试时闭上眼睛,只用听觉和键盘操作,体验视障用户的使用流程。
其他最佳实践
颜色对比度
前景和背景的对比度要足够高。WCAG 2.2 要求正文文本对比度至少 4.5:1,大文本至少 3:1。
可以用浏览器 DevTools 的 Color Contrast Checker 工具检查。
动画与 prefers-reduced-motion
部分用户对动画敏感,系统可以设置”减少动画”偏好。开发时应该尊重这个设置:
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
transition-duration: 0.01ms !important;
}
}
表单可访问性
// 用 label 关联输入框>
<label htmlFor="email">邮箱</label>
<input id="email" type="email" />
// 错误提示要用 aria-describedBy 关联
<input
id="email"
type="email"
aria-describedby="email-error"
aria-invalid={hasError}
/>
<span id="email-error" role="alert">
{errorMessage}
</span>
推荐资源
- WebAIM WCAG 清单:完整的无障碍检查清单
- WCAG 2.2 指南:官方无障碍标准
- The A11y Project:实用的无障碍开发资源
无障碍访问不是可选项。一个对所有人都友好的应用,才是真正好的应用。