Accessibility Trait:本質、種類、開発における動作方法

著者: IT Sectr 公開日: 2026-05-16 読了時間: 9 分

Accessibility Traitは、VoiceOverに対する要素の役割と動作を決定するiOS要素のプロパティです。トレイトはスクリーンリーダーに、要素がどのように読み上げられるべきか、どのジェスチャーが利用可能か(ボタン、ヘッダー、リンク、検索フィールドなど)を伝えます。Apple UIAccessibilityTraits、2024によると、システムは15以上の定数をサポートしており、ビットマスクを使用して組み合わせることができます。正しく選択されたトレイトは、VoiceOverユーザーのナビゲーション時間を最大50%節約します。

重要なポイント

  • Accessibility Trait — VoiceOverに対するiOS要素の役割。UIAccessibilityTraits定数で設定されます
  • トレイトは|演算子を使って組み合わせて、複雑な役割(ボタン+選択)を作成できます
  • 各要素は同時に複数のトレイトを持つことができますが、混乱を避けるため3〜4個までにすべきです
  • 間違ったトレイト(例:ボタンにStaticText)はインタラクションシナリオを壊します。ユーザーはジェスチャーが利用可能かどうかわかりません
  • Androidでは、AccessibilityNodeInfoのrole属性とclassName属性が相当します

Accessibility Traitとは

Accessibility Traitは、VoiceOverに意味的な役割を示すためにUIView要素に設定されるフラグです。トレイトはAppleのアクセシビリティ三要素(Label(名前)、Hint(説明)、Trait(役割))の1つです。iOSはUIAccessibilityTraitsビットマスク(UInt64)を使用し、各ビットは特定の役割に対応します。VoiceOverはLabelとHintの後に役割を読み上げます。「送信ボタン。フォームを開きます」— UIAccessibilityTraitButtonトレイトによって「ボタン」が追加されています。

デフォルトでは、UIButtonはUIAccessibilityTraitButtonを取得し、UILabelはUIAccessibilityTraitStaticTextを、UIImageViewはUIAccessibilityTraitImageを取得します。カスタムコントロールを使用する場合、開発者は手動でトレイトを設定する必要があります。Apple Human Interface Guidelines、2024は、これを「アクセシビリティを確保する上で最も重要なステップの1つ」と呼んでいます。

正しいトレイトがないと、ユーザーはどのジェスチャーを適用すべきかわかりません。シングルタップ(ボタン起動)、ダブルタップ(ズーム)、スワイプジェスチャー(トグル)などです。トレイトは、要素上でどのVoiceOverジェスチャーが有効になるかを決定します。

UIAccessibilityTraitsの技術的実装

UIAccessibilityTraitsはtypealias UInt64です。各トレイトは、正確に1ビットが設定された定数です。例えば、UIAccessibilityTraitButton = 0x0000000000000001、UIAccessibilityTraitLink = 0x0000000000000002、UIAccessibilityTraitHeader = 0x0000000000000008です。組み合わせはビットごとのORで実現されます:0x0001 | 0x0008 = 0x0009。VoiceOverはマスクを分析して動作を決定します。

iOSトレイトの主な種類

iOSは15以上のトレイト定数を提供しています。90%のシナリオで使用される主要なものを見てみましょう:

トレイト定数VoiceOverの動作
ButtonUIAccessibilityTraitButtonダブルタップで起動
HeaderUIAccessibilityTraitHeaderヘッダーによるクイックナビゲーション
LinkUIAccessibilityTraitLinkリンクとして起動
StaticTextUIAccessibilityTraitStaticText読み取り専用、起動なし
SearchFieldUIAccessibilityTraitSearchField特別な動作の検索フィールド
ImageUIAccessibilityTraitImage画像、起動ジェスチャーなし
SelectedUIAccessibilityTraitSelected「選択」状態
PlaysSoundUIAccessibilityTraitPlaysSound起動時に音を再生
KeyboardKeyUIAccessibilityTraitKeyboardKeyキーボードキー
TabBarUIAccessibilityTraitTabBarタブバー要素

定数はiOS 3.0以降UIKitで利用可能です。iOS 14+では、.accessibilityAddTraits()モディファイアを使用してSwiftUIでUIAccessibilityTraitsがサポートされました。

稀だが便利なトレイト

UIAccessibilityTraitAdjustable — 調整可能な値用(スライダー、ピッカー、音量スライダー)。VoiceOverはaccessibilityIncrementとaccessibilityDecrementで定義されたステップで値を変更するために上下にスワイプできます。UIAccessibilityTraitUpdatesFrequently — 頻繁に変化する値の要素用(タイマー、進行状況インジケーター)。VoiceOverは変更ごとに値を読み上げず、一時停止します。UIAccessibilityTraitAllowsDirectInteraction — ユーザーがVoiceOverジェスチャーを介さずに直接操作できる要素用(キーボード、描画)。

トレイトの組み合わせ

1つの要素に複数のトレイトを同時に持たせることができます — 組み合わせはビットごとのOR(|)で設定します。例:現在選択されているボタン — Button | Selected。VoiceOverは「選択済み。価格でフィルタリング。ボタン」と読み上げます。

コードでのトレイト設定:

swift
filterButton.accessibilityTraits.insert(.button)
filterButton.accessibilityTraits.insert(.selected)

// またはマスク経由:
filterButton.accessibilityTraits = [.button, .selected]

トレイトがデフォルトで設定されていないカスタムUIViewの場合:

swift
class CustomToggle: UIControl {
    override var accessibilityTraits: UIAccessibilityTraits {
        get {
            if isOn {
                return [.button, .selected]
            } else {
                return .button
            }
        }
        set {}
    }
}

組み合わせルール:要素あたり3〜4個以下のトレイト。過剰なトレイト(例:Button + Link + Header)はVoiceOverの読み上げが長くなり混乱を招きます。Appleによると、「追加のプロパティごとにユーザーの認知負荷が増加します」。

SwiftUI:トレイトモディファイア

SwiftUIでは、トレイトは.accessibilityAddTraits()と.accessibilityRemoveTraits()モディファイアを使用して設定します。例:Text(「タイトル」).font(.largeTitle).accessibilityAddTraits(.isHeader)。.isHeaderモディファイアはUIAccessibilityTraitHeaderを追加します。SwiftUIのトレイト一覧:.isButton、.isHeader、.isLink、.isSelected、.isImage、.isSearchField、.isKeyboardKey、.isStaticText、.isSummaryElement、.isToggle、.playsSound、.startsMediaSession、.updatesFrequently、.allowsDirectInteraction、.causesPageTurn、.isModal、.tabBar。

トレイト選択の一般的な間違い

Buttonの代わりにStaticText — 視覚的にボタンに見えるカスタムコントロールがデフォルトでStaticTextトレイトを取得します。VoiceOverは起動ジェスチャーを提供しないため、ユーザーは要素を「押す」ことができません。解決策:明示的に.buttonを設定します。

トレイトのない画像 — アクセシビリティが有効なUIImageViewは、実際には写真を拡大するボタンであってもImageトレイトを取得します。.buttonとLabel「写真を拡大」を割り当ててください。WWDC 2023、「Deliver an Exceptional Accessibility Experience」によると、新しいアプリバージョンでのアクセシビリティ回帰の40%は、トレイトの不一致が原因です。

すべての要素にHeader — Headerトレイトは画面の構造的なヘッダーを対象としています。すべてのUILabelをヘッダーにすると、「ヘッダー」モードのVoiceOverローターが役に立たなくなります — すべての単語で停止します。

修正方法:チェックリスト

  • インタラクティブなカスタム要素にはButton、Link、またはAdjustableトレイトを設定
  • セクションヘッダーにはHeaderトレイトを設定(StaticTextではない)
  • 画像ボタンには選択状態でButton + Selectedトレイトを設定
  • ジェスチャーのない要素 — StaticTextまたはImage(読み取り専用)

UIButtonをUIControlに置き換えたときの回帰バグ

トレイトを失う一般的な原因はリファクタリングです。開発者がカスタム表示のためにUIButtonをUIControlに置き換えると、UIButtonは自動的にButtonトレイトを取得しますが、UIControlは取得しません。リファクタリング後は、明示的にaccessibilityTraits = .buttonを設定する必要があります。コードレビューにチェックを追加してください:「UIButtonをUIControlに置き換えた場合 — トレイトを確認してください」。

トレイトと動的状態

状態が変化する要素(いいねボタンなど)では、トレイトを動的に変更する必要があります。「いいねされていない」状態ではButton、「いいねされている」状態ではButton + Selected + Image(アイコンがある場合)。VoiceOverの読み上げが変わります:「いいね。ボタン」vs「選択済み。いいね。ボタン」。Selectedトレイトが不十分な場合、状態を伝えるためにaccessibilityValueを使用します。購読ボタン、お気に入り、フィルター、トグルに適用されます。

Android相当:roleとclassName

Androidには、トレイトに直接相当するものはありません。ビットマスクの代わりに、以下が使用されます:

  • className — AccessibilityNodeInfo.classNameの値(android.widget.Button、android.widget.TextView)
  • role — XML属性(役割はViewの種類によって決定されます)
  • stateDescription — Selectedの相当:状態の説明を追加(有効/無効)

AndroidのカスタムViewでは、onInitializeAccessibilityNodeInfoをオーバーライドする必要があります:

kotlin
class CustomButton @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : View(context, attrs) {

    override fun onInitializeAccessibilityNodeInfo(
        info: AccessibilityNodeInfo
    ) {
        super.onInitializeAccessibilityNodeInfo(info)
        info.className = "android.widget.Button"
        info.isClickable = true
    }
}

Flutter開発者は、SemanticsウィジェットでsemanticsRoleパラメータを使用する必要があります:button、header、image、link、textFieldなど。さらに、semanticsLabelsemanticsHintが利用可能です — iOSの三要素Label + Hint + Traitの完全な相当です。

Web相当:WAI-ARIA role

モバイルアプリのWebバージョン(PWA、WebView)では、WAI-ARIAのrole属性が使用されます:role="button"、role="heading"、role="link"。これはaccessibilityTraitsの直接的な相当です。ハイブリッドアプリでは、WebViewがARIAロールをネイティブのアクセシビリティレイヤーに渡していることを確認してください。これには、iOSではUIAccessibilityContainerDataTableプロトコル、AndroidではsetAccessibilityDelegateを使用します。JavaScriptが有効なWebViewはARIAロールを正しく渡さない可能性があるため、個別にテストしてください。

AccessibilityNodeInfo:追加アクション

Androidでは、AccessibilityNodeInfoにカスタムアクションを追加できます:AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICKとACTION_LONG_CLICK。これは追加のジェスチャーを持つButtonトレイトに相当します。スライダーにはACTION_SET_PROGRESSを使用します — Adjustableに相当します。SpinnerとDatePickerには — ACTION_SET_SELECTION、ACTION_SET_DATE、ACTION_SET_TIMEを使用します。

トレイトの確認とテスト

Xcode Accessibility InspectorはiOSの主要ツールです:要素を選択してTraitsフィールドを表示すると、設定されたトレイトのリストが表示されます。「要素」モードのVoiceOverローターを使用すると、画面のすべてのコントロールをナビゲートできます。

トレイトを確認する自動化Swiftテスト:

swift
func testSubmitButtonTrait() {
    let app = XCUIApplication()
    app.launch()
    let submitButton = app.buttons["送信"]
    XCTAssertTrue(submitButton.isEnabled)
    // XCUIElementはトレイトへの直接アクセスを提供しません
    // ジェスチャー起動による確認
    submitButton.tap()
    XCTAssertTrue(app.staticTexts["フォームが送信されました"].exists)
}

VoiceOverによる手動確認:VoiceOverをオンにし、要素までスワイプしてダブルタップします — Buttonであれば要素が起動します。要素がダブルタップに反応しない場合、トレイトが間違っています。Rotorジェスチャーを使用してモードを切り替えます(「ヘッダー」、「リンク」、「ボタン」) — 各モードは対応するトレイトを持つ要素のみを表示します。

iOSでのトレイトのユニットテスト

iOS 14より前は、ユニットテストはaccessibilityTraitsに直接アクセスできませんでした。iOS 14以降、プロパティが利用可能になりました:XCTAssertEqual(customButton.accessibilityTraits, .button)。カスタムコントロールを検証するためにユニットテストでこれを使用してください。特にリファクタリングや親クラスの変更後は、新しいカスタムUIViewごとにトレイトの正確性をテストすることをお勧めします。

よくある質問

1つの要素にいくつのトレイトを割り当てられますか?

要素あたり3〜4個まで。それ以上多いとVoiceOverの読み上げが冗長になります。Button + Selected、Header + StaticTextの組み合わせを使用してください。

UIButtonのデフォルトのトレイトは何ですか?

UIAccessibilityTraitButtonです。iOSはすべてのUIButtonインスタンスに自動的に設定します。UIViewから継承してボタンを模倣する場合、トレイトを手動で設定する必要があります。

「Adjustable」トレイトはありますか?何のためですか?

はい、UIAccessibilityTraitAdjustable — 調整可能な値を持つ要素用です(スライダー、ピッカー、カウンター)。VoiceOverは上下にスワイプして値を変更し、現在の状態を読み上げることができます。

SwiftUIでトレイトを確認するには?

.accessibilityAddTraits()モディファイアを使用します:Text(「タイトル」).font(.title).accessibilityAddTraits(.isHeader)。このメソッドはiOS 14+で動作します。

カスタムコントロールにトレイトを設定しないとどうなりますか?

VoiceOverはNoneトレイトを割り当てます。要素には役割がなくなり、スクリーンリーダーはタイプを示さずにLabelのみを読み上げます。ユーザーは起動ジェスチャーが利用可能かどうかわかりません。

まとめ

  • Accessibility Trait — VoiceOverに対するiOS要素の役割を定義するビットマスクUIAccessibilityTraits(Button、Header、Link、StaticTextなど)
  • トレイトはビットごとのOR(Swiftでは[])で組み合わせ、要素あたり3〜4個まで
  • カスタムUIViewには明示的なトレイトが必要 — デフォルトではNoneまたはImageになる可能性があります
  • AndroidではAccessibilityNodeInfoのclassNameで、FlutterではsemanticsRoleで役割を設定
  • 間違ったトレイト(ボタンにStaticText)はVoiceOverシナリオを壊します:起動ジェスチャーなし
  • XcodeのAccessibility InspectorとVoiceOverローターでトレイトを確認
  • SwiftUIでは.accessibilityAddTraits()を使用して宣言的にトレイトを設定

ターンキー方式のモバイルアプリケーションを開発します

IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。

プロジェクトについて相談

こちらもお読みください