FE-14-可访问性 (a11y) 与国际化 (i18n)
本节目标:理解可访问性的核心原则(WCAG、ARIA),掌握国际化(i18n)方案,能构建对所有用户、所有语言友好的应用。
1. 什么是 a11y
a11y = accessibility(可访问性)。确保残障人士能使用产品。
残障类型:
- 视觉:盲、色弱、低视力
- 听觉:聋
- 运动:无法用鼠标、需要键盘或语音控制
- 认知:阅读障碍、注意力不集中
为什么重要:
- 道德:平等获取信息
- 法律:很多国家/地区强制要求(美国 ADA、欧洲 EAA、中国 GB/T 37668-2019)
- 商业:约 15% 人口有某种残障
- 改善 SEO 和可维护性
2. WCAG 标准
WCAG = Web Content Accessibility Guidelines,W3C 制定。四个原则(POUR):
| 原则 | 含义 | 示例 |
|---|---|---|
| Perceivable 可感知 | 用户能感知信息 | 文字替代、字幕 |
| Operable 可操作 | UI 组件可操作 | 键盘可达 |
| Understandable 可理解 | 信息和操作可理解 | 清晰语言 |
| Robust 健壮 | 兼容辅助技术 | 语义化 HTML |
三个等级:
- A:最低,必须满足
- AA:推荐,主流标准
- AAA:高级
3. 视觉无障碍
3.1 颜色对比度
对比度 ≥ 4.5:1(AA,正常文字),≥ 3:1(大文字/图标)
1 | ❌ 浅灰文字(#999)on 白色背景 → 对比度 2.85:1 |
工具:
- WebAIM Contrast Checker
- Chrome DevTools → 选元素 → Styles 面板 → 颜色块点击 → 显示对比度
- Lighthouse 审计
3.2 不依赖颜色
1 | <!-- ❌ 只用颜色表示状态 --> |
3.3 文字大小
1 | /* 用 rem 而不是 px(跟随用户设置) */ |
4. 键盘无障碍
4.1 焦点管理
1 | /* 永远不要完全隐藏焦点指示器! */ |
Tab 顺序:
1 | <!-- 默认按 DOM 顺序 --> |
4.2 跳过导航
1 | <a href="#main" class="skip-link">跳到主要内容</a> |
4.3 模态框焦点陷阱
1 | import { useRef, useEffect } from 'react'; |
更简单:用 Headless UI 或 Radix UI 的 Dialog。
5. ARIA 实战
ARIA 5 规则:
- 优先用原生 HTML
- 不要改原生语义
- 键盘可达
- 不隐藏可读元素
- 所有交互元素有可访问名
5.1 标签和描述
1 | <!-- 标签关联 --> |
5.2 实时区域
1 | <!-- polite:等当前读完后再说 --> |
5.3 复杂组件
手风琴:
1 | <div class="accordion"> |
Tab:
1 | <div role="tablist" aria-label="内容分类"> |
菜单:
1 | <button aria-haspopup="menu" aria-expanded="false" aria-controls="menu1"> |
6. 表单无障碍
1 | <form> |
7. 自动化测试工具
1 | # axe-core(推荐) |
其他工具:
- Lighthouse:Chrome DevTools → Lighthouse 面板
- WAVE:wave.webaim.org
- axe DevTools:浏览器扩展
- Pa11y:CI 友好
8. 国际化(i18n)
8.1 i18n vs l10n
- i18n(internationalization):国际化,开发时支持多语言
- l10n(localization):本地化,针对特定地区做翻译/调整
8.2 react-i18next
1 | npm install i18next react-i18next |
1 | // i18n/config.ts |
1 | // locales/zh.json |
1 | import { useTranslation } from 'react-i18next'; |
8.3 复数形式
i18next 内置 CLDR 复数规则:
- 中文:没有复数(永远是 “other”)
- 英文:one / other
- 阿拉伯:zero / one / two / few / many / other
1 | // en |
8.4 数字、日期、货币
1 | const number = 123456.789; |
8.5 Vue i18n(vue-i18n@9)
1 | import { createI18n } from 'vue-i18n'; |
9. RTL(从右到左)布局
阿拉伯语、希伯来语是 RTL 方向。
1 | /* 用 logical 属性 */ |
1 | <html dir="rtl" lang="ar"> |
10. 实战 checklist
a11y:
- 所有图片有
alt(或alt=""表示装饰) - 颜色对比度 ≥ 4.5:1
- 键盘可达(Tab 顺序合理)
- 焦点指示器可见(不要
outline: none) - 表单字段有关联
<label> - 标题层级不跳级
- 模态框有焦点陷阱和 ESC 关闭
- 错误消息用
aria-live - 跳过导航链接
- 用 axe / Lighthouse 跑过
i18n:
- 文案不硬编码在 JSX
- 复数形式正确处理
- 日期/数字/货币用 Intl API
- 字体支持目标语言(中文 vs 阿拉伯文)
- RTL 布局(如果是阿拉伯语等)
- URL 反映语言(
/zh/aboutvs/en/about) -
<html lang="...">标记 - SEO hreflang 标签
小结
| 主题 | 关键点 |
|---|---|
| WCAG | 4 原则(POUR)、AA 标准 |
| 对比度 | ≥ 4.5:1(AA),大文字 ≥ 3:1 |
| 键盘 | 焦点可见、Tab 顺序、模态框陷阱 |
| ARIA | 补充 HTML 语义,不是替代 |
| i18n | 用 i18next / vue-i18n,不硬编码 |
| 复数 | 用 CLDR 规则 |
| Intl API | 数字/日期/货币/复数 |
| RTL | 用 logical 属性 |
核心原则:
- a11y 不是事后补救,从设计阶段就考虑
- HTML 优先,ARIA 补充
- 测试用真实辅助技术(屏幕阅读器、键盘)
- i18n 在第一天就集成,不要等
- 多用 Intl API,少自己实现
下一节(最后一节)讲前端安全:XSS、CSRF、CSP、SameSite 策略。
- 本文作者: CoderSong
- 本文链接: https://jack-song-gif.github.io/2026/09/18/FE-14-可访问性a11y与i18n/
- 版权声明: 本博客所有文章除特别声明外,均采用 MIT 许可协议。转载请注明出处!