ハイライト
visionOS は空間コンピューティングに完全なアクセシビリティ体系をもたらしました。VoiceOver はピンチジェスチャーの組み合わせで 3D 空間をナビゲートし、RealityKit の AccessibilityComponent で 3D エンティティをスクリーンリーダーが認識でき、Dwell Control で視線だけの操作が可能になり、head anchor の代替案と Reduce Motion 対応で動きに敏感なユーザーも快適に使えます。
主要内容
課題: 3D 空間のアクセシビリティは未開拓の領域
従来の画面では、VoiceOver は UI 要素を 1 次元の順序で走査します — 上から下、左から右。開発者はボタンに accessibilityLabel、画像に accessibilityDescription を付ければ、ほぼ十分です。
空間コンピューティングはこれをすべて覆します。visionOS では UI 要素が 3 次元空間に分布します。ボタンが前方 2 メートルにあり、別のボタンが左 45 度、3 メートル先にあるかもしれません。VoiceOver は単純に「上から下」では走査できず、空間関係を理解する必要があります。
さらに厄介なのは、3D シーンのオブジェクトが UIButton や UILabel ではなく、3D モデル、マテリアル、アニメーションで構成される RealityKit エンティティであることです。これらは VoiceOver から完全に見えません。追加対応をしなければ、3D シーンの雲、木、キャラクターは視覚障害のあるユーザーには何もない空間です。
操作方式も変わりました。visionOS にタッチスクリーンはなく、目の視線と指のピンチで操作します。運動障害のあるユーザーにとって新たな課題です — ピンチができない人、視線を一点に安定させられない人がいます。
Apple のアプローチ: アクセシビリティ体系を 3D に持ち込む
visionOS はシステムレベルでアクセシビリティ体系全体を再設計しました。VoiceOver は画面座標の走査ではなく空間認識ナビゲーション — 空間オーディオでオブジェクトの方位を示し、ユーザーが空間内の位置を「聞いて」把握できます。
3D コンテンツには AccessibilityComponent を導入 — 任意のエンティティをアクセシビリティシステムが認識できる RealityKit コンポーネントです。エンティティにラベル、値、特性、カスタム操作を設定できます。UIKit/SwiftUI のアクセシビリティ API と同じ設計思想で、3D シーン向けに適応されています。
運動アクセシビリティでは、visionOS が Dwell Control(視線滞留制御)と Switch Control(外部スイッチ制御)を提供します。前者は対象を見つめ一定時間保つだけで操作をトリガー — 指のピンチは不要。後者は Bluetooth スイッチデバイスでシステム全体を制御できます。
詳細
RealityKit エンティティを VoiceOver に認識させる
visionOS では RealityKit エンティティはデフォルトでアクセシビリティシステムから見えません。AccessibilityComponent を明示的に作成してエンティティに付与する必要があります(05:28):
var accessibilityComponent = AccessibilityComponent()
accessibilityComponent.isAccessibilityElement = true
accessibilityComponent.traits = [.button, .playsSound]
accessibilityComponent.label = "Cloud"
accessibilityComponent.value = "Grumpy"
cloud.components[AccessibilityComponent.self] = accessibilityComponent
// ...
var isHappy: Bool {
didSet {
cloudEntities[id].accessibilityValue = isHappy ? "Happy" : "Grumpy"
}
}
キーポイント:
AccessibilityComponent()は RealityKit エンティティのアクセシビリティ属性を記述するコンポーネントインスタンスを作成isAccessibilityElement = trueで VoiceOver がこのエンティティを発見可能にtraitsを.buttonと.playsSoundに設定すると VoiceOver はボタンで音を鳴らす要素と認識 — 「ボタン」と聞いたユーザーはアクティベートできると分かるlabelは VoiceOver が読み上げる名前、valueは現在の状態cloud.components[AccessibilityComponent.self] = accessibilityComponentで RealityKit エンティティにコンポーネントを付与- 状態変化時は
didSetでaccessibilityValueを更新 — VoiceOver が自動で状態変化を読み上げ
RealityKit エンティティにアクティベーション操作を追加
VoiceOver で読み上げるだけでは不十分 — ユーザーは操作できる必要があります。systemActions で VoiceOver ユーザーがジェスチャーで 3D オブジェクトをアクティベートできます(08:04):
var accessibilityComponent = AccessibilityComponent()
accessibilityComponent.isAccessibilityElement = true
accessibilityComponent.traits = [.button, .playsSound]
accessibilityComponent.label = "Cloud"
accessibilityComponent.value = "Grumpy"
accessibilityComponent.systemActions = [.activate]
cloud.components[AccessibilityComponent.self] = accessibilityComponent
// ...
content.subscribe(to: AccessibilityEvents.Activate.self, componentType: nil) { activation in
handleCloudCollision(for: activation.entity, gameModel: gameModel)
}
キーポイント:
systemActions = [.activate]でアクティベート操作を登録 — VoiceOver ユーザーはピンチジェスチャーでトリガーcontent.subscribe(to: AccessibilityEvents.Activate.self, ...)でアクセシビリティアクティベーションイベントを監視- コールバックは
activationを受け取り、activation.entityからアクティベートされたエンティティを取得 handleCloudCollisionはカスタムハンドラ — 例: 雲に音を鳴らす、表情を変えるcomponentType: nilはすべてのエンティティタイプのアクティベーションをフィルタなしで監視
コンテキスト内の重要イベントをアナウンス
空間 App では、シーンの変化がユーザーの視野外で起こることがあります。背後からオブジェクトが現れたり、遠くで注意が必要な出来事が起きたりします。VoiceOver ユーザーに能動的に通知する必要があります(09:23):
AccessibilityNotification.Announcement("8 clouds in front of you").post()
キーポイント:
AccessibilityNotification.Announcementでアクセシビリティアナウンス通知を作成.post()でシステムに送信 — VoiceOver が括弧内のテキストを読み上げ- ユーザーが見えない可能性のある重要な変化に使う — ゲームスコア、新しい敵、カウントダウン
- アナウンスは簡潔で情報密度が高く、「何が」「どこで」を直接記述
head anchor コンテンツの代替案を提供
空間 App では UI 要素を head anchor(頭部追従)にできます — 常にユーザーの視線に追従します。しかし乗り物酔いしやすい人や前庭障害のある人には不快感を与えることがあります。visionOS はユーザー設定を検出する API を提供します(13:15):
// SwiftUI
@Environment(\.accessibilityPrefersHeadAnchorAlternative)
private var accessibilityPrefersHeadAnchorAlternative
// UIKit
AXPrefersHeadAnchorAlternative()
NSNotification.Name.AXPrefersHeadAnchorAlternativeDidChange
キーポイント:
- SwiftUI では
@EnvironmentでaccessibilityPrefersHeadAnchorAlternativeを読み取り — ブール値は head anchor の代替が必要かを示す - UIKit では
AXPrefersHeadAnchorAlternative()で現在の設定を取得 AXPrefersHeadAnchorAlternativeDidChangeで UIKit 開発者が設定変化を監視trueのとき、head anchor の UI を world anchor(空間の固定位置)またはウィンドウ内に変更- この設定はアクセシビリティ設定でシステムが一元管理 — App 側のスイッチは不要
Reduce Motion 設定への適応
visionOS も Reduce Motion(動きの削減)をサポートします。大量のアニメーション、パーティクル効果、空間移動を含む App では、この設定を確認して敏感なユーザーの不快感を避けます(15:04):
// SwiftUI
@Environment(\.accessibilityReduceMotion)
private var accessibilityReduceMotion
// UIKit
UIAccessibility.isReduceMotionEnabled
UIAccessibility.reduceMotionStatusDidChangeNotification
キーポイント:
accessibilityReduceMotionはシステムの Reduce Motion 設定を反映- 有効時は以下を削減または無効化: 大きなオブジェクトアニメーション、パーティクルシステム、視差スクロール、激しいカメラ移動
isReduceMotionEnabledは UIKit の読み取り専用プロパティ — 起動時と設定変化時に確認reduceMotionStatusDidChangeNotificationで設定変化にリアルタイム対応- 一般的な適応: バネアニメーションをシンプルなフェードに、3D 回転効果を除去
字幕設定の確認
空間コンピューティングでも聴覚アクセシビリティは重要です。visionOS はシステムレベルのクローズドキャプション設定をサポート — App はこの設定を確認して字幕表示を決めます(23:35):
UIAccessibility.isClosedCaptioningEnabled
UIAccessibility.closedCaptioningStatusDidChangeNotification
キーポイント:
isClosedCaptioningEnabledはユーザーがシステム設定でクローズドキャプションを有効にしているかを返す- 音声コンテンツ(会話、ナレーション、効果音)を含む App はこの値に基づき文字字幕を表示
closedCaptioningStatusDidChangeNotificationでユーザーが設定を切り替えたときにリアルタイム更新- 字幕は聴覚障害ユーザーだけでなく、騒がしい環境やサイレントモードのユーザーも助ける
重要ポイント
-
RealityKit ゲームに完全な VoiceOver サポートを追加: visionOS App に 3D インタラクティブオブジェクトがある場合、各インタラクティブエンティティに
AccessibilityComponentを付与し、.label、.value、.traits、.systemActionsを設定。なぜやるか: visionOS にタッチスクリーンはなく、VoiceOver は視覚障害ユーザーの唯一の操作手段。アクセシビリティ未対応なら完全に使えない。始め方: App 内のすべてのインタラクティブ RealityKit エンティティを洗い出し、上記AccessibilityComponentスニペットで設定し、シミュレータで VoiceOver テスト。 -
空間認識のイベントアナウンスを実装: 重要なシーン変化で
AccessibilityNotification.Announcementを使い能動的に通知 — 例:「3 体の敵が後ろにいます」「右側のドアが開きました」。なぜやるか: 空間 App では多くの出来事が視野外で起こる。視覚障害ユーザーには追加の聴覚キューが必要。始め方:「起きたがユーザーが見えない」すべてのイベントを洗い出し、トリガー点に.post()を追加し、アナウンス文に方位情報を含める。 -
Head Anchor 設定を検出して適応: 起動時に
accessibilityPrefersHeadAnchorAlternativeを読み取り、trueなら頭部追従の HUD、メニュー、プロンプトを world anchor またはウィンドウ内表示に変更。なぜやるか: head anchor コンテンツは視野端を常に占め、前庭に敏感なユーザーに不快感を与える可能性。代替案で利用のハードルを大きく下げられる。始め方: App 内のすべての head anchor UI を監査し、各 UI の非 head anchor フォールバックレイアウトを用意、@Environment値で切り替え。 -
動き効果の Reduce Motion 適応を構築:
accessibilityReduceMotionを読み取り、trueなら大きなアニメーションをすべてシンプルな遷移に置き換え。なぜやるか: visionOS の空間アニメーションは平面画面より強烈 — オブジェクトが 3D で移動・回転・拡大縮小。動きに敏感なユーザーには App が使えなくなる。始め方: 主要アニメーションに完全版と簡略版の 2 バージョンを作り、環境変数で選択、reduceMotionStatusDidChangeNotification発火時に動的切り替え。 -
すべての音声コンテンツに字幕サポートを追加:
isClosedCaptioningEnabledを確認し、字幕有効時に音声の文字説明を表示。なぜやるか: visionOS の空間オーディオは没入感があるが、聴覚障害ユーザーは情報にアクセスできない。字幕は情報の平等な取得の鍵。始め方: 会話、ナレーション、重要な効果音の文字説明を用意し、音声再生時に字幕設定を確認。
関連セッション
- Perform accessibility audits for your app — XCTest で App のアクセシビリティ準拠を自動チェック。本文の API と組み合わせて実装を検証
- Build accessible apps with SwiftUI and UIKit — SwiftUI と UIKit のアクセシビリティ新機能。visionOS API と同じ設計思想
- Meet Assistive Access — 認知障害ユーザー向け Assistive Access モード。visionOS もサポート
- Design for spatial input — 目と手のインタラクション設計。空間入力の理解がアクセシビリティ適応の出発点に
- Build spatial experiences with RealityKit — RealityKit 入門。本文の AccessibilityComponent は RealityKit エンティティシステムの上に構築
コメント
GitHub Issues · utterances