Accessibility Label は、VoiceOver (iOS) または TalkBack (Android) がフォーカス時に検出するインターフェイス要素の名前です。iOS では、プロパティは accessibilityLabel と呼ばれ、Android では contentDescription がテキストを含まない要素に対して使用されます。Apple Developer Documentation, 2024によると、ラベルはアクセシビリティの基礎です: これがなければ、ユーザーは要素を識別できません。ラベルは画面内で独自であり、要素の本質を明確な言語で反映する必要があります。
メインポイント
Accessibility Label は、アシスティブテクノロジー向けに要素の名前を定義する文字列プロパティです。ユーザーが VoiceOver を有効にして画面をスワイプすると、スクリーンリーダーがフォーカスされた要素の Label を読み上げます。ラベルがなければ、ユーザーは要素のタイプ(“ボタン”、“画像”)のみを聞くことになり、目的は伝わりません。
Google I/O 2024、“Accessibility Testing”によると、ストアアプリの重大なアクセシビリティ違反の 35% がラベルの欠如または不適切さに関連しています。Android の Accessibility Scanner は、ラベルの欠如を最も重大なエラーとして検出します。
基本的な制限: Label に要素のタイプを含んではなりません。VoiceOver と TalkBack は、アナウンスに自動的に役割(ボタン、ヘッダー、リンク)を追加します。Label が“送信ボタン”の場合、ユーザーは “送信ボタン、ボタン” と聞こえます — 重複です。
WCAG 4.1.2 (レベル A) は、すべてのユーザーインターフェイス要素がプログラム的に判別可能な 名前、役割、値を持つことを必須としています。Accessibility Label が名前を提供します。Label が欠けている場合、基準を満たしておらず、アプリケーションは基本認証をパスしません。
iOS では、accessibilityLabel は UIAccessibility プロトコルからすべての UIView に継承されます。要素がテキストを含む場合(タイトル付き UIButton、テキスト付き UILabel)、Label は自動的にそのテキストに設定されます。UIImageView、カスタムコントロール、コンテナの場合は、Label を手動で設定する必要があります。
カスタムテーブルセルの例:
class CustomTableViewCell: UITableViewCell {
let titleLabel = UILabel()
let priceLabel = UILabel()
override func awakeFromNib() {
super.awakeFromNib()
self.isAccessibilityElement = true
self.accessibilityLabel =
"\(titleLabel.text ?? "") - \(priceLabel.text ?? "")"
}
}
カスタム UIView の場合、accessibilityLabel ゲッターをオーバライドできます:
class RatingView: UIView {
var rating: Int = 5
override var accessibilityLabel: String? {
get { return "評価: \(rating) / 5" }
set {}
}
}
Apple HIG, 2024 のアドバイス: 要素が複数のサブ要素(例えば、名前と価格を持つ商品カード)から構成されている場合、これらを複合 Label をもつ単一のアクセシビリティ要素に統合します。親要素で isAccessibilityElement = true、子要素で false を設定します。
UILabel が NSAttributedString を使用する場合、accessibilityLabel はデフォルトで .string(プレーンテキスト)となります。構文的に異なる値(例えば、記号アイコンが ★ 文字の代わりに “星” と読まれる場合)を渡す必要がある場合は、accessibilityLabel を明示的に設定します。VoiceOver は Unicode 文字を意味あるものとして読み上げません。
Android では、contentDescription が ImageView、ImageButton、カスタム View の Label として機能します。テキストが組み込まれた TextView や Button の場合、contentDescription を設定する必要はありません — TalkBack が自動的にテキストを読み上げます。
Kotlin によるプログラム的設定:
binding.iconStar.contentDescription = "お気に入りの商品"
// 複数の要素を持つカスタム View の場合
binding.customCard.setContentDescription(
"\(title) を \(price) で")
装飾要素の XML:
<ImageView
android:contentDescription="@null"
android:src="@drawable/divider"
android:importantForAccessibility="no" />
importantForAccessibility = “no” プロパティは、要素をアクセシビリティツリーから完全に除外します。iOS の同等は isAccessibilityElement = false です。
Jetpack Compose では、Label は semantics 修飾子を通じて設定されます:
Image(
painter = painterResource(R.drawable.ic_search),
contentDescription = "商品を検索",
modifier = Modifier.semantics {
contentDescription = "商品を検索"
}
)
Compose では、contentDescription は Image の 必須 パラメーターです — これがなければコードはコンパイルできません(警告)。これにより、API デザインを通じて強制的にアクセシビリティが向上します。
Accessibility Label は “この要素は何か?” という問いに答えます。Hint (iOS の accessibilityHint、Android の contentDescription 内の追加テキスト) は “操作すると何が起こりますか?” を説明します。VoiceOver はこれらを順番にアナウンスします: まず Label、それから Hint です。
削除ボタン の例:
Deque University, 2024によると、Label と Hint を適切に区分することで、VoiceOver ユーザーのタスク完了率が 28% 向上します。認知障害のあるユーザーは特に Hint に依存しています: 説明なしで “削除” を押すことに不安を感じた場合、40% がアクションを拒否します。
よくある誤り: Label に “削除” の代わりに “削除ボタン” と記入すること。要素のタイプ(ボタン)は VoiceOver によって特徴を通じて自動的に追加されます。その結果、ユーザーには “削除ボタン、ボタン” と聞こえます — 重複です。正しい Label: “削除”、Hint: “選択した写真を削除します”。
ラベルのローカライゼーション は必須です — 標準的なメカニズムを通じて行います: iOS の NSLocalizedString、Android の文字列リソース @string/ 。ローカライズせずに英語の結合で Label を設定しないでください。
W3C WCAG 2.2 に基づく良い Label のルール:
アプリ全体で Label に 単一の用語集 を使用します。ある画面で “お気に入り”、別の画面で “ブックマーク” と書いてあると、ユーザーは迷惑います。アクセシビリティ用語集テーブルを作成します — デザイナーやローカライザーと連携します。
入力フィールド (UITextField, EditText) の場合、Label はプレースホルダーまたはフィールドのラベルと一致する必要があります。ただし、テキストを入力すると、プレースホルダーは消えます。永続的な名前には accessibilityLabel、フィールドの現在の内容には accessibilityValue を使用します — これが WCAG 4.1.2 標準です。解決策: accessibilityLabel を静的に(フィールドのラベルと同じ)、accessibilityValue を動的に(入力されたテキストと同じ)設定します。iOS ではこれは自動的ですが、カスタムフィールドの場合は accessibilityValue をオーバライドして手動で設定します。VoiceOver が “, テキストフィールド” ではなく “メールアドレス、例@ドメイン.com、テキストフィールド” と読むことを確認します。
自動テスト は、すべての画面で Label の正確さを保証する唯一の方法です。iOS は .label へのアクセスを持つ XCUIApplication を提供し、Android は AccessibilityCheckRule と setContentDescription を提供します。
iOS のテスト例:
func testLabelsAreUnique() {
let app = XCUIApplication()
app.launch()
let allButtons = app.buttons.allElementsBoundByIndex
let labels = allButtons.compactMap { $0.label }
let uniqueLabels = Set(labels)
XCTAssertEqual(labels.count, uniqueLabels.count,
"重複した Label が見つかりました")
}
Espresso を使った Android の例:
@Test
fun testButtonHasAccessibilityLabel() {
onView(withId(R.id.btnSubmit))
.check(matches(
withContentDescription(containsString("送信"))
))
}
手動テスト: VoiceOver (iOS) または TalkBack (Android) を有効にし、画面上のすべての要素を右にスワイプします。各要素は 意味あるアナウンス を得る必要があります。“ボタン” または “画像” のみが聞こえる場合、Label が欠けています。
Label を設定すると、VoiceOver ユーザーは ローター を使ってクイックナビゲーションができます: “ボタン”、“見出し”、“リンク” などのモード。Label が正しく設定されていれば、VoiceOver は要素を対応するローターモードに含めます。すべてのボタンが “ボタン” モードで、すべての見出しが “見出し” モードで表示されることを確認します。
Label は、VoiceOver の検索にも影響します。ユーザーが検索モードで単語を入力すると、VoiceOver は一致する Label を持つ要素にフォーカスを移動させます。したがって、Label にはユーザーが検索するキーワードを含める必要があります。
パイプラインに Label 検査を追加します。iOS では、fastlane scan とともに XCUITest を使用します。Android では、空の contentDescription を検出する AccessibilityCheckRule を使用して Accessibility Test Framework を使用します。これにより、新しい画面をマージする際のリグレッションを防げます。
よくある質問
Label は要素を識別し(“検索”)、Hint はアクションの結果を説明します(“検索画面を開きます”)。VoiceOver はフォーカス時に即座に Label をアナウンスし、詳細説明 モードで Hint をアナウンスします。
iOS では、UILabel は自動的にテキストに等しい accessibilityLabel を得ます。追加の設定は不要です。Android の TextView も同様に動作します。
親 View で isAccessibilityElement = true を設定し、子要素から結合されたテキストを戻すように accessibilityLabel をオーバライドします。複雑なコンポーネントの場合は、セパレーターで結合します。
繰り返し要素に コンテキスト を追加します: “iPhone 15 を購入”、“iPhone 15 Pro を購入”。UI テストを通じてチェックを自動化します — すべての Label を収集し、重複がないことを確認します。
いいえ。要素を隠すには、iOS で isAccessibilityElement = false または Android で importantForAccessibility = “no” を使用します。空の Label は要素を隠しません — スクリーンリーダーは “タイトルなし” と読み上げます。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。