iOS 无障碍最佳实践:接触更多用户并满足合规要求
发布日期: 2026-05-10
最后更新: 2026-05-10
作者: AppPreflight Team
概述
无障碍设计不仅在道德上是正确的——它也是一个商业机会。全球有 10 亿多残疾人。使应用可访问会增加可寻址市场,通常符合法律合规要求。Apple 通过更好的可见性奖励可访问的应用。本指南涵盖实施对每个人都有利的无障碍功能。
1. 为什么无障碍很重要
市场机会
- 全球人口的 15-20% 有残疾
- 老年人越来越多地使用应用
- 家长在双手忙碌时使用语音控制
- 许多暂时性残疾(手臂骨折、明亮阳光)
法律合规
美国:《美国残疾人法》(ADA)
- 应用必须无障碍供残疾人使用
- 如果用作公共场所适用
- 违规可能导致诉讼
欧盟:《欧洲无障碍法》
- 移动应用必须无障碍
- 提供技术规范
- 不合规会被罚款
其他地区
- 加拿大:AODA(安大略省残疾人无障碍法)
- 澳大利亚:《残疾歧视法》
- 许多国家有类似要求
Apple 的偏好
- 无障碍是应用审核标准的一部分
- 无障碍应用可能被拒绝
- 良好无障碍的应用会被推荐
- 无障碍影响 App Store 排名
2. 核心无障碍原则
WCAG 指南(网络内容无障碍指南)
适用于 iOS 应用:
1. 可感知
- 内容对所有用户可见/可听
- 不仅依赖颜色
- 视频字幕
2. 可操作
- 键盘导航
- 触摸目标足够大(最小 44x44 点)
- 内容不被困在特定输入方法
3. 可理解
- 清晰的语言和说明
- 一致的导航
- 有用的错误消息
4. 健壮
- 与辅助技术兼容
- 与 VoiceOver 一起工作
- 支持动态文字大小调整
3. VoiceOver 实现
什么是 VoiceOver
盲人/低视力用户的屏幕阅读器:
- 通过音频描述屏幕上的元素
- 允许通过手势导航
- 读取文本、描述、标签
启用 VoiceOver
设置 > 无障碍 > VoiceOver > 打开
代码实现
// ❌ 错误 - 无无障碍标签
Button(action: {}) {
Image(systemName: "checkmark")
}
// ✅ 正确 - 清晰的无障碍标签
Button(action: {}) {
Image(systemName: "checkmark")
.accessibility(label: Text("Mark as complete"))
}
// 更好:如果有帮助,包括提示
Button(action: {}) {
Image(systemName: "checkmark")
.accessibility(label: Text("Mark as complete"))
.accessibility(hint: Text("Mark this task as completed"))
}
UIKit 示例
let button = UIButton()
button.accessibilityLabel = "Mark as complete"
button.accessibilityHint = "Mark this task as completed"
button.accessibilityTraits = .button
自定义操作
VStack {
Text("Item")
.accessibility(customActions: [
AccessibilityCustomAction(
name: "Mark as complete",
target: self,
selector: #selector(markComplete)
),
AccessibilityCustomAction(
name: "Delete",
target: self,
selector: #selector(delete)
)
])
}
@objc func markComplete() { ... }
@objc func delete() { ... }
4. VoiceOver 测试
在设备上测试
1. 设置 > 无障碍 > VoiceOver > 打开
2. 主屏幕按钮:单击(说出元素)
3. 主屏幕按钮:双击(激活)
4. 向右滑动:下一个元素
5. 向左滑动:上一个元素
要测试的常见问题
☐ 所有交互元素都有标签
☐ 图像有有意义的描述
☐ 状态信息以文本形式传达(不仅是颜色/图标)
☐ 导航顺序有意义
☐ 表单字段清晰标记
☐ 按钮执行其标签建议的操作
☐ 无键盘陷阱
☐ 文本在大字体时可读
☐ 链接可区分
5. 动态类型和文本缩放
支持动态文本大小
Apple 的无障碍功能允许用户选择的文本大小(从"小"到"无障碍超大")。
实现
// SwiftUI
Text("Hello")
.font(.body) // 自动随系统设置缩放
.dynamicTypeSize(.large) // 可选:如果需要固定大小
// UIKit
label.font = UIFont.preferredFont(forTextStyle: .body)
label.adjustsFontForContentSizeCategory = true
测试
设置 > 无障碍 > 显示和文本大小 > 更大的无障碍大小
在以下大小测试应用:小、中、大、超大、+ 3 个无障碍级别
验证:文本可读、布局不中断、交互工作
6. 颜色和对比度
颜色对比度要求
WCAG AA 标准(最低)
- 常规文本:4.5:1 对比度
- 大文本(18pt+):3:1 对比度
测试
使用对比度检查工具:
- 对比度(webachecker.com)
- 输入前景和背景颜色
- 检查 4.5:1 或 3:1 标准
不要仅依赖颜色
// ❌ 错误 - 仅使用颜色
if error {
textField.backgroundColor = .red // 仅颜色
}
// ✅ 正确 - 颜色 + 文本 + 图标
if error {
textField.backgroundColor = .red
errorLabel.text = "Invalid email address"
errorIcon.image = UIImage(systemName: "exclamationmark.circle.fill")
}
深色模式支持
// 支持浅色和深色模式
extension UIColor {
static let appBackground = UIColor { traitCollection in
if traitCollection.userInterfaceStyle == .dark {
return UIColor.black
} else {
return UIColor.white
}
}
}
7. 触摸目标大小
最小触摸目标大小
Apple 推荐:44x44 点
// ❌ 太小(对运动困难的用户来说很难)
Button(action: {}) {
Image(systemName: "plus")
.frame(width: 24, height: 24)
}
// ✅ 正确大小
Button(action: {}) {
Image(systemName: "plus")
}
.frame(width: 44, height: 44)
.contentShape(Rectangle()) // 触摸目标延伸到框架
交互元素之间的间距
最小值:相邻按钮之间 8 点
// ❌ 按钮太近
HStack {
Button("Yes") { }
Button("No") { }
}
// ✅ 充足的间距
HStack(spacing: 16) {
Button("Yes") { }
Button("No") { }
}
8. 键盘导航
完整的键盘无障碍
某些用户无法使用触摸:
- VoiceOver 与键盘
- 外部键盘
- 交换机控制用户
// ✅ 启用键盘导航
TextField("Username", text: $username)
.textContentType(.username)
.keyboardType(.asciiCapable)
// Tab 顺序
struct ContentView: View {
var body: some View {
VStack {
TextField("Email", text: $email)
.focusable()
.focused($focusedField, equals: .email)
SecureField("Password", text: $password)
.focusable()
.focused($focusedField, equals: .password)
Button("Login") { }
.focusable()
}
}
}
测试键盘导航
设置 > 无障碍 > 键盘 > 完整键盘访问 > 打开
然后按 Tab 浏览所有交互元素
验证:所有按钮/输入可访问、顺序合理
9. 视频和音频无障碍
视频字幕
所需内容:
- 所有带音频的视频
- 言语、对话、音效
- 音乐(如果对内容重要)
// 将字幕添加到 AVPlayer
player.currentItem?.externalMetadata = [/* caption tracks */]
// 在应用资产中
// MyVideo.mp4 + MyVideo.srt(字幕文件)
音频描述
对于无法看到的用户:
- 描述视觉内容的单独音频轨道
- 集成到主要音频
- 启用/禁用选项
10. 测试无障碍
内置无障碍检查器
Xcode > Open Developer Tool > Accessibility Inspector
功能:
- 显示无障碍层次结构
- 突出显示焦点
- 使用模拟 VoiceOver 进行测试
- 报告无障碍问题
手动测试清单
- VoiceOver:所有内容可读且可导航
- 键盘:所有功能无需触摸即可访问
- 语音控制:"显示标签"显示所有元素
- 文本大小:应用在最大设置下正常工作
- 深色模式:正确工作
- 颜色对比:符合 4.5:1 或 3:1 标准
- 触摸目标:所有按钮最少 44x44
- Alt 文本:所有图像都有有意义的描述
- 视频:存在字幕和描述
- 动作:无自动播放动画造成的分散
无障碍测试工具
- Apple 的无障碍检查器(免费,内置)
- WAVE(网络无障碍工具,某些 iOS 功能)
- 颜色对比度分析器
- Lighthouse(用于网络组件)
11. 无障碍的 App Store 审核
Apple 的无障碍审核
Apple 特别检查:
- VoiceOver 功能
- 动态类型支持
- 颜色对比
- 键盘导航
- 触摸目标大小
- 图像的有意义的 alt 文本
常见拒绝原因(无障碍)
"Your app contains images but most lack descriptions.
Users with VoiceOver cannot understand image content."
解决方案:为所有有意义的图像添加 accessibilityLabel
"Interactive elements cannot be accessed via keyboard.
Users who cannot use touch cannot use these features."
解决方案:使用 focusable() 实现完整的键盘导航
无障碍合规清单
- 所有交互元素都有无障碍标签
- VoiceOver 已测试且完全工作
- 颜色对比符合 4.5:1 标准
- 文本使用动态类型缩放
- 触摸目标最少 44x44 点
- 键盘导航完整
- 图像有有意义的 alt 文本
- 视频有字幕
- 视觉内容的音频描述
- 无内容被困(所有可访问)
- 可禁用动作/动画
- 无障碍检查器显示无警告
后续步骤
- 在设备上启用 VoiceOver
- 使用 VoiceOver 导航您的应用
- 修复发现的任何问题
- 使用完整键盘导航进行测试
- 检查颜色对比
- 在大尺寸上测试动态类型
- 让残疾人进行测试
- 修复剩余问题
- 自信地提交
无障碍应用不仅在道德上是正确的——它们是更聪明的商业选择。