WCAG 達成基準 · Level A

WCAG 2.5.3: 名前に含まれるラベル

WCAG 2.5.3 は、視覚的なテキストラベルを持つインタラクティブなコンポーネントについて、その視覚的なテキストを含むアクセシブルネームを持つことを求めています。これにより、音声入力ユーザーが画面に表示されているテキストを話すことでコントロールを操作できるようにします。視覚的なラベルとアクセシブルネームの不一致は、音声による操作ナビゲーションを妨げ、何百万人ものユーザーにとっての信頼を損ないます。

  • Level A

このルールの意味

\n

WCAG 2.5.3 — Label in Name(名前にラベルを含める)— は、可視テキストラベルを持つあらゆるユーザーインターフェイスコンポーネントに適用されます。この達成基準は、そのコンポーネントのアクセシブルネームが、可視ラベルのテキストと完全に一致するか、少なくとも可視ラベルのテキストを部分文字列として含んでいることを求めます。これにより、ユーザーが画面上であるラベルを目にしているにもかかわらず、支援技術や音声認識ソフトウェアが裏側ではまったく別の名前を認識してしまう状況を防ぎます。

\n

アクセシブルネームとは、アクセシビリティツリーに公開され、スクリーンリーダー、音声コントロールソフトウェア、その他の支援技術によって使用される名前です。これは、要素の可視テキストコンテンツ、aria-label 属性、aria-labelledby 参照、title 属性、関連付けられた <label> 要素など、さまざまなソースから取得される場合があります。開発者がアクセシブルネームを上書きし、その中に可視ラベルのテキストが含まれていない場合、不一致が発生し、この達成基準は不適合となります。

\n

影響を受ける要素には、テキストを表示し、かつアクセシブルネームを持つあらゆるインタラクティブコンポーネントが含まれます。ボタン、リンク、可視ラベルを持つフォーム入力、メニュー項目、タブ、チェックボックス、ラジオボタン、カスタム ARIA ウィジェットなどです。段落や見出しなどの非インタラクティブ要素は、この達成基準の対象外です。

\n

適合とみなされる条件: アクセシブルネームが、先頭と末尾の空白を無視したうえで、可視ラベルのテキストを連続した部分文字列として含んでいること。大文字・小文字は区別しません。たとえば、ボタンに「Search Products」と表示されている場合、アクセシブルネームが「Search Products Now」であれば、「Search Products」を含んでいるため適合です。一方、「Find Products」というアクセシブルネームは、可視テキストを含まないため不適合です。

\n

不適合とみなされる条件: アクセシブルネームが可視ラベルとまったく異なる場合、またはアクセシブルネームが可視ラベルの意味のある一部を省略している場合です。たとえば、見た目のボタンに「Buy Now」と表示されているにもかかわらず、aria-label='Purchase item' が付与されている場合、この達成基準は不適合です。同様に、「Contact Us」と表示されているリンクが、aria-label='Reach our team' を持つ要素でラップされている場合も不適合です。

\n

WCAG で定義されている公式の例外: ラベルが純粋に象徴的または絵文字的で、テキストによる同等表現が存在しないコンポーネント(たとえば、可視テキストのないアイコンのみのボタン)には、この達成基準は適用されません。また、テキストが純粋に装飾目的の要素の一部であり、意味的な情報を持たない場合も対象外です。数学表記や、テキスト表現が発話可能な単語に対応しない言語固有の状況も除外されます。さらに、アクセシブルネームが意図的に追加の文脈で拡張されている場合でも、可視テキストがアクセシブルネームの中に含まれていれば適合とみなされます。

\n\n

なぜ重要か

\n

この達成基準は主に、Dragon NaturallySpeaking(現在の Dragon Professional)、Windows Speech Recognition、Apple の Voice Control などの音声認識ソフトウェアに依存するユーザーを保護します。これらのユーザーは、画面上で目にするラベルを発話することで、インターフェイス要素をナビゲートし、操作します。アクセシブルネームが可視ラベルと一致しない場合、ソフトウェアはユーザーが発話した名前に対応する要素を見つけられず、そのコントロールはマウスやキーボードなしでは事実上操作不能になります。反復性ストレス障害、筋ジストロフィー、脳性まひ、脊髄損傷などの運動障害があるユーザーにとって、音声入力はコンピューター操作の主な、あるいは唯一の手段であることが多く、1つのボタンの不一致が、ワークフロー全体へのアクセスを妨げることがあります。

\n

スクリーンリーダーユーザーも影響を受けます。スクリーンリーダーが画面上に表示されているものとは異なるアクセシブルネームを読み上げると、認知的な混乱が生じます。たとえば、視覚と聴覚の両方のフィードバックを同時に利用する弱視のユーザーなど、視力がありつつスクリーンリーダーも使用するユーザーは、画面で読んでいる内容と異なるものを読み上げられることで、インターフェイスのメンタルモデルが崩れてしまいます。

\n

認知障害のあるユーザーは、読んでいる内容と話される(またはアナウンスされる)内容が一致していることで恩恵を受けます。予期しない名前の変化は認知負荷を高め、特に記憶障害のあるユーザーや、初めてシステムの使い方を学んでいるユーザーにとって、混乱や誤操作の原因となります。

\n

具体的な実世界のシナリオ: 「Place Order」というテキストが視覚的に表示されたボタンを持つ EC サイトのチェックアウトページを考えてみましょう。開発者は、より説明的な名前だと考えて aria-label='Submit purchase form' を追加します。Dragon NaturallySpeaking を使用している顧客が「Click Place Order」と発話すると、Dragon はアクセシビリティツリーをスキャンしますが、「Place Order」という名前の要素が見つからず、そのボタンをアクティブにできません。顧客はマウス操作に切り替えない限り購入を完了できませんが、それができない場合もあります。その結果、取引は放棄されます。これは仮想的なレアケースではなく、小売や銀行のウェブサイトに対する自動監査で頻繁に見つかる一般的な失敗パターンです。

\n

世界保健機関によると、世界中で 10 億人を超える人々が何らかの障害を抱えて生活しています。2023 年の WebAIM Million レポートでは、WCAG 2.5.3 のラベル不一致が監査対象ページの有意な割合で見つかっており、その多くは善意ながら誤って適用された ARIA によって引き起こされていました。アクセシビリティにとどまらず、ラベリングの一貫性は SEO の向上にもつながります。リンクやボタンのテキストを関連性評価のためにインデックスする検索エンジンクローラーは、アクセシブルネームと可視テキストが一致していると、より意味のあるシグナルを受け取ることができるからです。

\n\n

関連する Axe-core のルール

\n
    \n
  • label-content-name-mismatch: これは WCAG 2.5.3 に関連する主要な自動ルールです。このルールは、ボタン、リンク、role='button'role='link'role='menuitem'role='tab' などの ARIA ロールを持つ要素など、可視テキストラベルとアクセシブルネームの両方を持つインタラクティブ要素をチェックします。アクセシブルネームが可視テキストを部分文字列として含んでいない(大文字・小文字は区別しない)要素を検出してフラグを立てます。このルールは、アクセシブルネームが aria-labelaria-labelledby によって上書きされ、その結果、画面上のテキストと乖離している要素を特に対象とします。axe はこれらをインパクトレベル「serious」の違反として報告します。なぜなら、音声入力ユーザーがコントロールをアクティブにすることを直接妨げるからです。
  • \n
  • 自動検出の限界: axe-core のような自動ツールは、可視テキストが要素内のプレーンテキストノードとしてレンダリングされ、アクセシブルネームが静的な aria-label または aria-labelledby 属性から取得される場合には、不一致を確実に検出できます。しかし、次のような場合には手動テストが必要です。(1) 可視テキストが CSS の ::before::after 疑似要素を通じてレンダリングされている場合(ブラウザや支援技術のバージョンによって、これらがアクセシビリティツリーに含まれるかどうかが異なる可能性があります);(2) ラベルがページ読み込み後に JavaScript によって動的に挿入される場合;(3) 可視テキストにアイコンや画像ベースのテキストが含まれ、そのテキスト部分を推測する必要がある場合;(4) 要素の計算されたアクセシブルネームが、複数の要素を連結する複雑な aria-labelledby チェーンを伴う場合。このようなケースでは、スクリーンリーダーを使用する人間のテスターが、実際に何が読み上げられているかと、画面上で何が見えているかを比較して検証する必要があります。
  • \n
\n\n

テスト方法

\n
    \n
  1. axe DevTools または Lighthouse による自動スキャン: axe DevTools ブラウザ拡張機能(Chrome または Firefox)をインストールするか、Chrome DevTools で Lighthouse のアクセシビリティ監査を実行します。完全にレンダリングされたページでスキャンを実行します。インタラクティブ要素を含む動的コンテンツ、モーダル、展開されたメニューなどがあれば、それらが開いている状態で実行してください。axe の結果パネルで、ルール ID label-content-name-mismatch でフィルタリングします。フラグが立てられた各要素には、可視テキストと並んで計算されたアクセシブルネームが表示されるため、不一致が一目で分かります。要素セレクターをメモし、DOM を調査してアクセシブルネームが上書きされている原因を特定します。Lighthouse でも、「Accessibility」カテゴリ内で同じ不適合が WCAG 2.5.3 への参照付きで表示されます。
  2. \n
  3. ブラウザ DevTools による手動検査: ブラウザのアクセシビリティパネルを開きます(Chrome DevTools → Elements → Accessibility タブ、または Firefox DevTools → Accessibility タブ)。可視テキストを持つ各インタラクティブ要素を選択します。要素の「Computed Properties」セクションで Name フィールドを確認します。この値を可視ラベルと比較します。計算された名前が可視ラベルのテキストを部分文字列として含んでいない場合、その要素は 2.5.3 に不適合です。
  4. \n
  5. NVDA + Firefox によるスクリーンリーダーテスト: NVDA を起動した状態で Firefox を開きます。Tab キーを使って各インタラクティブ要素に移動します。NVDA がその要素の名前として何を読み上げるかを聞きます。読み上げられる名前と画面上に表示されているテキストとの間に不一致がないか確認します。NVDA の要素リスト(Insert+F7)を使用して、すべてのリンクとボタンを一覧表示し、読み上げられる名前と可視ラベルをまとめて比較します。
  6. \n
  7. JAWS + Chrome によるスクリーンリーダーテスト: JAWS を起動した状態で Chrome を開きます。すべてのインタラクティブコントロールを Tab キーで順に移動します。JAWS はアクセシブルネームの後にロールを読み上げます。読み上げられる名前に可視テキストが含まれていない場合、その要素を記録します。さらに、JAWS の「ブラウズモード」と仮想ビューアを使用して、各コントロールの計算されたアクセシブルネームを確認します。
  8. \n
  9. VoiceOver + Safari(macOS/iOS)によるスクリーンリーダーテスト: VoiceOver を有効にします(macOS では Command+F5)。Tab キーまたは VO+右矢印キーを使用してインタラクティブ要素をナビゲートします。VoiceOver は各コントロールのアクセシブルネームを読み上げます。iOS では、1 本指で右にスワイプして要素間を移動し、名前とラベルの不一致がないかを聞き取ります。
  10. \n
  11. Voice Control(macOS/iOS)または Dragon による音声認識テスト: macOS の Voice Control を有効にします(システム設定 → アクセシビリティ → Voice Control)。「Show names」と発話して、すべてのインタラクティブ要素のラベルを表示させます。Voice Control によって表示されるラベルが、画面上の可視テキストと一致していることを確認します。可視ラベルのテキストを発話してコントロールをアクティブにしようとします。可視名で反応しないコントロールは、2.5.3 の不適合です。Windows で Dragon NaturallySpeaking が利用可能な場合は、「Click [label]」コマンドを使って同様のテストを行います。
  12. \n
\n\n

修正方法

\n\n

aria-label で上書きされたボタン — 誤った例

\n
<!-- FAIL: aria-label が可視テキスト「Search」を完全に\n     「Execute query」に置き換えており、音声入力が機能しない -->\n<button aria-label='Execute query'>\n  Search\n</button>
\n\n

aria-label で上書きされたボタン — 正しい例

\n
<!-- PASS: 不一致のある aria-label を完全に削除する。\n     ボタンの可視テキスト「Search」が自動的にアクセシブルネームになる。\n     音声ユーザーは「Click Search」と言ってボタンを操作できる。 -->\n<button>\n  Search\n</button>\n\n<!-- PASS(別案): 追加の文脈が必要な場合は、\n     アクセシブルネームに可視テキストを必ず含める。 -->\n<button aria-label='Search products'>\n  Search\n</button>
\n\n

aria-labelledby が無関係なテキストを指しているリンク — 誤った例

\n
<!-- FAIL: aria-labelledby が見出し「Our Services」を参照しているが、\n     リンクの見た目のテキストは「Learn more」であり、\n     アクセシブルネームが「Learn more」ではなく「Our Services」になってしまう -->\n<h2 id='services-heading'>Our Services</h2>\n<p>\n  <a href='/services' aria-labelledby='services-heading'>Learn more</a>\n</p>
\n\n

aria-labelledby が無関係なテキストを指しているリンク — 正しい例

\n
<!-- PASS: aria-labelledby を使って、リンク自身のテキストと見出しを連結する。\n     アクセシブルネームは「Learn more Our Services」となり、\n     可視ラベル「Learn more」を含んでいる。 -->\n<h2 id='services-heading'>Our Services</h2>\n<p>\n  <a href='/services' id='learn-link' aria-labelledby='learn-link services-heading'>\n    Learn more\n  </a>\n</p>\n\n<!-- PASS(別案): 可視リンクテキスト自体を自己説明的にして、\n     上書きが不要なようにする。 -->\n<a href='/services'>Learn more about our services</a>
\n\n

aria-label が可視テキストと矛盾しているアイコンボタン — 誤った例

\n
<!-- FAIL: ボタンにはカートアイコンとテキスト「Cart」が表示されている。\n     aria-label 'View shopping basket' には「Cart」が含まれておらず、\n     「Click Cart」と言っても音声ユーザーは反応を得られない。 -->\n<button aria-label='View shopping basket'>\n  <svg aria-hidden='true'><!-- cart icon --></svg>\n  Cart\n</button>
\n\n

aria-label が可視テキストと矛盾しているアイコンボタン — 正しい例

\n
<!-- PASS: aria-label に可視テキスト「Cart」が部分文字列として含まれている。\n     音声ユーザーは「Click Cart」でも「Click View Cart」でも操作できる。 -->\n<button aria-label='View Cart'>\n  <svg aria-hidden='true'><!-- cart icon --></svg>\n  Cart\n</button>\n\n<!-- PASS(推奨): aria-label を削除し、アイコンをツリーから隠す。\n     ボタンのテキストコンテンツ「Cart」がそのままアクセシブルネームになる。 -->\n<button>\n  <svg aria-hidden='true' focusable='false'><!-- cart icon --></svg>\n  Cart\n</button>
\n\n

可視ラベルを持つフォーム入力だが aria-label が不一致 — 誤った例

\n\n

(Content truncated due to token limit — please retry this article.)