ハイライト
Apple は Xcode 15 で XCTest フレームワークに
performAccessibilityAudit()メソッドを追加しました。開発者は UI テストで VoiceOver ラベル、コントラスト、Dynamic Type など 10 種類のアクセシビリティ問題をワンクリックで自動チェックし、クロージャで誤検知をフィルタし、CI/CD フローにアクセシビリティテストを統合できます。
主要内容
課題: アクセシビリティテストがいつも後回しになる理由
多くの開発者はアクセシビリティ対応をしたいが、プロジェクトが逼迫するとアクセシビリティ最適化が真っ先に削られる。理由はシンプル — テストコストが高すぎる。
従来のアクセシビリティテスト: VoiceOver を手動で有効にし、画面を要素ごとにスワイプ・タップし、ラベルが UI 要素を正しく記述しているか耳で確認。このプロセスにはいくつかの問題がある:
- 時間がかかる: 中程度の複雑さの画面を完全テストするのに 10〜20 分
- リグレッションテストが難しい: UI を変更するたびに手動で再テストが必要
- 見落としやすい: 目と耳が疲労し、コントラスト問題やフォント拡大後のレイアウト問題を見逃しやすい
- 自動化できない: CI で自動的にアクセシビリティチェックを走らせるツールがない
結果: ほとんどの App はリリース前に 1 回だけアクセシビリティテストをするか、まったくしない。
Apple のソリューション: 自動アクセシビリティ監査
Xcode 15 は XCUIApplication.performAccessibilityAudit() を導入し、UI テストで 10 種類のアクセシビリティ問題を自動検出します:
- Dynamic Type: フォント拡大後に要素がクリップされないか
- コントラスト: 文字と背景のコントラストが WCAG AA に達しているか
- 要素の存在: インタラクティブ要素が支援技術から見えるか
- ラベル: ボタン・画像に記述的な
accessibilityLabelがあるか - 特性: インタラクティブ要素が正しい特性(例:
.button)を宣言しているか - ヒント: 状態変化に
accessibilityHintが提供されているか - アクセシビリティ: 無効状態が正しく反映されているか
- アクション: カスタムインタラクションに
accessibilityCustomActionsがあるか - ヒットテスト: タップ領域が十分大きいか(最低 44×44 ポイント)
- キーボードフォーカス: キーボードナビゲーション順序が妥当か
これらのチェックは UI テスト内で通常の XCTAssert と同様に実行 — 問題があればテスト失敗、成功すれば続行。継続的インテグレーションにアクセシビリティテストを組み込み、毎ビルドで実行できます。
詳細
基本用法: ワンクリックで App 全体を監査
最もシンプルな用法は 3 行だけ(02:52):
func testAccessibility() throws {
let app = XCUIApplication()
app.launch()
try app.performAccessibilityAudit()
}
キーポイント:
XCUIApplication()は UI テストの App プロセスプロキシ、launch()で App を起動performAccessibilityAudit()は現在表示中のすべての UI 要素を走査し、10 種類のアクセシビリティ問題を順にチェック- 問題が見つかると例外をスローし、テスト失敗
- 現在の画面に表示されているすべての要素をチェック —
isHittable == falseの要素も含む
誤検知のフィルタ: カスタム監査ルール
実際の使用では、一部の「問題」は設計判断でありバグではない — 純粋に装飾的な背景画像にラベルがない、ブランドカラー要件による低コントラストの文字など。
Apple は各問題発見時に無視するか決められるクロージャパラメータを提供(09:57):
try app.performAccessibilityAudit(for: [.dynamicType, .contrast]) { issue in
var shouldIgnore = false
// "My Label" のコントラスト問題を無視
if let element = issue.element,
element.label == "My Label",
issue.auditType == .contrast {
shouldIgnore = true
}
return shouldIgnore
}
キーポイント:
for:で監査するタイプを指定。空配列[]で 10 種類すべてを監査issueはAccessibilityIssue型 —element(問題の UI 要素)、auditType(問題タイプ)、message(具体的な説明)を含む- クロージャが
trueを返すと問題を無視、falseでテスト失敗 - 要素の
label、identifier、elementTypeなどで誤検知か判断可能 - このクロージャは今回の監査呼び出しにのみ影響 — グローバル設定は変更しない
監査範囲の制御: 特定要素だけを支援技術に公開
VoiceOver にはアクセスさせたいが UI テストにはアクセスさせたくない要素(内部レイアウトコンテナなど)、またはその逆のケースがあります。
iOS 17 は accessibilityElements を追加し、VoiceOver が見える要素範囲を精密に制御(08:40):
// VoiceOver にこの 2 要素だけ見せる
view.accessibilityElements = [quoteTextView, newQuoteButton]
キーポイント:
accessibilityElementsはUIViewとNSViewのプロパティ- 設定後、支援技術はこの配列の要素だけを見る — 子ビューは無視
- 内部レイアウト構造を公開したくないシーン向けの「ホワイトリスト」モード
UI テストの可視性も個別に制御可能(14:07):
// UI テストにこの 3 要素だけアクセスさせる
view.automationElements = [imageView, quoteTextView, newQuoteButton]
キーポイント:
automationElementsは XCTest が見える要素を制御- テストコードを実装詳細に結合させたくないシーンに有用
- 設定後、
XCUIApplicationのクエリは配列内の要素だけを見つける
監査結果の解釈: 失敗の修正方法
performAccessibilityAudit() が問題を見つけると、テストログに次のような情報が出力されます:
Accessibility Issue - Contrast
Element: Button, label = "Submit"
Issue: Contrast ratio is 2.1:1, which is below the WCAG AA standard of 4.5:1 for normal text
一般的な修正方法:
| 問題タイプ | 典型的な原因 | 修正方法 |
|---|---|---|
| コントラスト | 文字色と背景が近すぎる | 文字色の明度を上げるか背景色を下げる、または太字に(小さいサイズは 3:1 で可) |
| ラベル | ボタン/画像に accessibilityLabel がない | 装飾要素は accessibilityLabel = ""、機能要素は記述的ラベル |
| Dynamic Type | 固定高さの制約でフォント拡大後にクリップ | contentHuggingPriority と compressionResistancePriority、または UIStackView で子ビューを適応 |
| アクション | カスタムジェスチャーに代替操作がない | VoiceOver ユーザー向けに accessibilityCustomActions を追加 |
重要ポイント
1. すべての UI テストにアクセシビリティ監査を追加
今日から、主要画面の UI テストすべてに try app.performAccessibilityAudit() を追加。テストスイートへの「アクセシビリティ保険」のようなもの — 誰かがその画面のアクセシビリティを壊せば、テストが即座に失敗します。
実装手順:
- プロジェクトでカバレッジが最も高い UI テストを見つける(通常はログインフロー、ホームナビゲーションなど)
app.launch()の後にtry app.performAccessibilityAudit()を 1 行追加- テストを 1 回実行し、初回発見問題数を記録
- 1 つずつ修正するか、フィルタクロージャで既知の問題を一時的に無視し、後で整理
2. 「アクセシビリティチェックリスト」テンプレートを作成
多くのアクセシビリティ問題はパターン化されています: ナビゲーションバーの戻るボタンにラベルがない、カードビューのタップ領域が小さすぎる、チャートに accessibilityValue がない。プロジェクトレベルのチェックリストを作り、新画面完成時に照合。
テンプレート例:
- すべてのボタンに
accessibilityLabelまたは意味のあるtitleがある - 装飾的な画像は
accessibilityElementsHidden = true - タップ可能要素の最小サイズ 44×44 ポイント
- 文字と背景のコントラスト >= 4.5:1(通常サイズ)または 3:1(大きい/太字)
- カスタムジェスチャーに
accessibilityCustomActionsまたは代替操作がある
3. ブランドカラーシステム向けのアクセシビリティコントラストテストを構築
多くの App のブランドカラーシステムはコントラストを考慮せず設計され、App 全体で文字が読みにくくなります。スクリプトでブランドカラーパレットとすべての文字色のコントラストを自動計算し、「アクセシビリティに優しい配色提案」を生成。
実装の考え方:
func calculateContrastRatio(foreground: UIColor, background: UIColor) -> CGFloat {
// WCAG コントラストを計算
// 式: (L1 + 0.05) / (L2 + 0.05)、L1 は明るい方の相対輝度
// 戻り値 >= 4.5 で AA 基準を満たす
}
Design Token 内のすべての foregroundColor と backgroundColor の組み合わせを走査し、4.5:1 未満の組み合わせリストを出力。
4. automationElements で UI テストの脆弱性を減らす
UI テストは界面調整(中間コンテナビューの追加、ビュー階層の変更など)でよく失敗します。automationElements で本当に重要なテストアンカーだけを公開し、テストコードを実装詳細に結合させない。
適用シーン:
- 内部サブビューがよく変わる複雑なカスタムコントロール(カレンダー、チャート)
- サードパーティコンポーネントライブラリで、ライブラリ内部構造にテストを依存させたくない場合
- UI テストからデバッグ用補助ビューを隠す必要がある場合
5. アクセシビリティ問題の段階的処理フローを確立
すべてのアクセシビリティ問題を即座に修正する必要はありません。深刻度で段階分け:
- P0: 基本使用を阻害(主要ボタンにラベルなし、コントラストが低すぎて全く見えない)— 今回のリリース前に必ず修正
- P1: 特定ユーザーグループに影響(カスタムジェスチャーに代替操作なし)— 次バージョンで修正
- P2: 体験の最適化(Hint 不足、アクション説明が不十分)— 段階的に改善
- P3: 誤検知または設計判断(ブランドカラーのコントラストがやや低いが他で補完)— 理由を記録し、監査クロージャでフィルタ
これでリリース速度とアクセシビリティ品質のバランスが取れます。
関連セッション
- What’s new in accessibility — iOS 17、iPadOS 17、macOS Sonoma の最新アクセシビリティ機能とフレームワーク
- Testing tips and tricks — より良いテストを速く書くテクニック。UI テストとユニットテスト戦略を含む
- Meet Apple Store Accessibility: A new way to shop — Apple Store のアクセシビリティ機能が障害のあるユーザーのショッピング体験をどう向上させるか
- Design for accessibility — 視覚、運動、認知障害ユーザーを含むすべての人に適したインターフェースの設計
- Accessibility in SwiftUI — SwiftUI がアクセシブルなインターフェース構築をいかに簡単にし、体験をカスタマイズするか
コメント
GitHub Issues · utterances