AppPreflight Logo
AppPreflight
loading
返回指南

iOS 无障碍最佳实践:接触更多用户并满足合规要求

AppPreflight Team
2026-05-10
5 分钟阅读

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 文本
  • 视频有字幕
  • 视觉内容的音频描述
  • 无内容被困(所有可访问)
  • 可禁用动作/动画
  • 无障碍检查器显示无警告

后续步骤

  1. 在设备上启用 VoiceOver
  2. 使用 VoiceOver 导航您的应用
  3. 修复发现的任何问题
  4. 使用完整键盘导航进行测试
  5. 检查颜色对比
  6. 在大尺寸上测试动态类型
  7. 让残疾人进行测试
  8. 修复剩余问题
  9. 自信地提交

无障碍应用不仅在道德上是正确的——它们是更聪明的商业选择。


这篇指南对你有帮助吗?