本当に役立つ ARIA ラベルの開発者向けガイド
ARIA ラベルは、魔法のアクセシビリティ層ではありません。適切に使えば、コントロールを理解しやすくします。安易に使えば、有用なテキストを隠し、混乱しやすいインターフェイスを生みます。
目次
ARIA ラベルは名前のためのものです。言い訳のためではありません
ARIA は有用ですが、不明瞭な HTML を補修するためのパッチとして使われることがよくあります。チームが問題に陥るのは、まさにそこです。
最も一般的な例は aria-label です。一見すると無害に見えます。文字列を追加し、linter を満たし、先へ進む。しかし、アクセシブルな名前は飾りではありません。多くの支援技術が、ユーザーがボタン、リンク、フォームフィールド、見出し、ランドマーク、コントロールを移動するときに提示する名前です。
その名前が曖昧だったり、重複していたり、古くなっていたり、表示ラベルと異なっていたりすると、インターフェイスは使いにくくなります。さらに悪い場合もあります。aria-label は、DOM にすでに存在していたより良いテキストを上書きしてしまうことがあります。
目標は、ARIA をさらに追加することではありません。目標は、各インターフェイス要素の名前、ロール、状態、目的を明確にすることです。
アクセシブルな名前を平易に言うと
ほとんどのインタラクティブ要素には、アクセシブルな名前があります。スクリーンリーダーは、その名前を使って要素が何であるかを読み上げます。
例えば:
<button>Save changes</button>
スクリーンリーダーは「Save changes, button」のように読み上げることができます。ロールはネイティブの button 要素から来ます。名前はその中のテキストから来ます。
これが理想的なケースです。表示テキストとアクセシブルな名前が一致しています。
ARIA のラベル付け属性が役立つのは、表示されているインターフェイスだけでは完全な名前を提供できない場合、または名前を別の要素から取得する必要がある場合です。主な属性は次のとおりです。
aria-label: 要素に直接文字列を提供します。aria-labelledby: そのテキストが名前になる 1 つ以上の要素を指します。aria-describedby: 主な名前ではなく、補足説明テキストを指します。
この 3 つは関連していますが、互換ではありません。
第一のルール: ネイティブ HTML と表示ラベルを優先する
コントロールに表示テキストを置けるなら、まずそうしてください。
こちらの方が優れています:
<button>Delete invoice</button>
こちらよりも:
<button aria-label="Delete invoice">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
2 つ目のパターンは、アイコンのみのボタンでは有効です。しかしデザインが表示テキストを許容できるなら、表示テキストはすべての人の助けになります。スクリーンリーダーユーザー、音声認識ユーザー、認知負荷のある人、素早く画面を見渡す人、翻訳ツールを使う人に役立ちます。
これはアクセシビリティ作業で繰り返し出てくるテーマです。ネイティブ HTML と目に見えるアフォーダンスは、隠れたメタデータより多くの問題を解決します。同じ原則は、ボタンのセマンティクス全般にも当てはまります。チームで UI コントロールを監査しているなら、このガイドの補足として アクセシブルな Web ボタンのための簡潔で実践的なチェックリスト が役立ちます。
aria-label が適切な道具である場合
要素にアクセシブルな名前が必要で、参照できる適切な表示テキストがない場合に aria-label を使います。
典型的なケースは、アイコンのみのボタンです:
<button aria-label="Search">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<!-- icon -->
</svg>
</button>
これは妥当です。表示されているアイコンは検索を示唆しますが、SVG パス自体は信頼できる名前を提供しません。aria-label がそれを補います。
その他の良い例には、次のようなものがあります。
- “X” だけで表された閉じるボタン。
aria-label="Product"のように、より具体的な名前が必要なナビゲーションランドマーク。- 表示されている文脈がボタンテキストの一部ではない、繰り返しのコントロール。
例えば:
<nav aria-label="Primary">
...
</nav>
<nav aria-label="Footer">
...
</nav>
どちらもナビゲーションランドマークですが、ラベルがあることで、ユーザーはランドマーク単位で移動するときに区別しやすくなります。
aria-label が不適切な道具である場合
テストが「ラベルが必要」と言っているからという理由だけで aria-label を追加しないでください。まずマークアップを修正します。
悪い例:
<div role="button" tabindex="0" aria-label="Submit">Submit</div>
より良い例:
<button>Submit</button>
最初の例は、不要な作業を生みます。キーボード操作、無効状態、フォームの挙動、ネイティブボタンがすでに提供している期待される動作を、自分たちで再現しなければなりません。
また、表示テキストの意味を変えるような形で aria-label を使って名前を付け直すことも避けてください。
<button aria-label="Delete invoice">Remove</button>
これは小さな違いに見えますが、音声入力に頼るユーザーを混乱させることがあります。表示されているボタンが “Remove” と言っているのに、アクセシブルな名前が “Delete invoice” であれば、ユーザーが “click Remove” と言っても期待どおりの結果にならない可能性があります。WCAG の「label in name」要件が存在するのは、まさにこのためです。表示テキストは一般に、アクセシブルな名前に含まれているべきです。
より良い例:
<button aria-label="Remove invoice">Remove</button>
さらに良い場合が多い例:
<button>Remove invoice</button>
表示テキストがすでにあるなら aria-labelledby を使う
ラベルテキストがすでにページ上にある場合、通常は aria-label より aria-labelledby の方が適しています。
例:
<h2 id="billing-title">Billing address</h2>
<section aria-labelledby="billing-title">
...
</section>
この section のアクセシブルな名前は、表示されている見出しから取得されます。文字列の重複を避けられるため、翻訳ミスや古くなったラベルを減らせます。
これはフォームグループで特に役立ちます:
<fieldset aria-labelledby="shipping-speed-title">
<legend id="shipping-speed-title">Shipping speed</legend>
<label>
<input type="radio" name="shipping" value="standard">
Standard
</label>
<label>
<input type="radio" name="shipping" value="express">
Express
</label>
</fieldset>
多くの場合、ネイティブの legend だけで十分で、ARIA は不要です。重要なのは、表示ラベルを主にすることです。ARIA は既存の意味を接続するためのものであり、その非公開の別バージョンを作るためのものではありません。
aria-describedby はヘルプテキストに使い、名前には使わない
説明はラベルではありません。
次のフィールドを考えてみます:
<label for="password">Password</label>
<input id="password" type="password" aria-describedby="password-help">
<p id="password-help">Use at least 12 characters.</p>
アクセシブルな名前は “Password” です。説明は “Use at least 12 characters.” です。スクリーンリーダーは両方を読み上げることがありますが、それぞれの役割は異なります。
これはしないでください:
<input type="password" aria-label="Use at least 12 characters">
これはフィールドを概念ではなく指示文で名付けています。フォームを移動するユーザーは、まずそのフィールドが何かを知り、その後でどの制約が適用されるかを知りたいのです。
この区別は、エラー状態でも重要です:
<label for="email">Email</label>
<input
id="email"
type="email"
aria-invalid="true"
aria-describedby="email-error"
>
<p id="email-error">Enter an email address in the format [email protected].</p>
ラベルは安定したままです。エラーメッセージは補足的な文脈になります。
繰り返しのコントロールには固有の名前が必要
リストやカードでは、ARIA ラベルが必要になることがよくあります。
悪い例:
<button>Delete</button>
<button>Delete</button>
<button>Delete</button>
スクリーンリーダーユーザーがボタン単位で移動すると、文脈なしに “Delete, button” を 3 回聞くことになるかもしれません。
良い例:
<button aria-label="Delete report: Q4 revenue">Delete</button>
<button aria-label="Delete report: Hiring plan">Delete</button>
<button aria-label="Delete report: Vendor list">Delete</button>
これは aria-label の正当な使い方です。表示テキストは簡潔なままにしつつ、アクセシブルな名前には対象を含めています。
ただし、このパターンは慎重に使ってください。対象名が近くに表示されているなら、aria-labelledby の方が保守しやすい場合があります:
<article>
<h3 id="report-q4">Q4 revenue</h3>
<button aria-labelledby="delete-q4 report-q4" id="delete-q4">Delete</button>
</article>
アクセシブルな名前は “Delete Q4 revenue” になります。これにより、レポートタイトルを属性内で重複させずに済みます。
すべてにラベルを付けない
すべての要素に ARIA ラベルが必要なわけではありません。
静的テキストには通常不要です。装飾アイコンにも不要です。コンテナにも、意味のあるランドマークやウィジェットロールがない限り不要です。過剰なラベル付けは、ページを騒がしくし、移動しにくくすることがあります。
画像については、画像固有のモデルを使います。意味のある画像には有用な alt が必要で、装飾画像には空の alt="" が必要です。適切な画像テキストの代わりに ARIA ラベルを使わないでください。チームでこれらの概念が混ざっているなら、実用的な画像 alt テキスト を見直し、画像の代替テキストとコントロール名を分けて考えてください。
よくある間違いは、すべての SVG に aria-label を付けることです。SVG がボタンの中にあり、そのボタンにすでに名前がある場合、通常そのアイコンは支援技術から隠すべきです:
<button aria-label="Open menu">
<svg aria-hidden="true" focusable="false">...</svg>
</button>
そうしないと、ブラウザーと支援技術の組み合わせによって、ユーザーが重複した、あるいは奇妙な読み上げを聞く可能性があります。
コードだけでなく、計算された名前を確認する
アクセシビリティの不具合は、マークアップがもっともらしく見えるためにコードレビューをすり抜けることがよくあります。
現代のブラウザー開発者ツールでは、計算されたアクセシビリティツリーを確認できます。Chrome、Edge、Firefox、Safari では、要素を検査し、role、name、description などのアクセシビリティ情報を探します。確認することは 3 つです。
- ロールは期待どおりか?
- アクセシブルな名前は明確で具体的か?
- 説明は名前を置き換えずに役立っているか?
そのうえで、実際のスクリーンリーダーでいくつかのフローをテストします。基本的な問題を見つけるために、支援技術の専門家にフルタイムでなる必要はありません。macOS には VoiceOver が組み込まれています。Windows では NVDA が広く使われており、無料です。モバイルでは、関連する場合に iOS の VoiceOver と Android の TalkBack でテストします。
自動化ツールは有用ですが、“Open”、“Read more”、“Delete” が十分な文脈を持っているかを確実に判断することはできません。自動化は判定者ではなく、網として扱ってください。これはパフォーマンス監査にも似ています。レポートは疑わしい箇所を示してくれますが、影響の解釈はやはり必要です。慌てずに Lighthouse レポートを読む ときに勧めているのと同じ落ち着いた姿勢が、ここでも当てはまります。
実践的なレビューチェックリスト
ARIA ラベルをリリースする前に、次のことを確認してください。
- これは代わりにネイティブ HTML にできないか?
- ラベルとして使うべき表示テキストがあるか?
- 表示テキストがある場合、アクセシブルな名前にそれが含まれているか?
- 繰り返しのコントロールは、視覚的な文脈から切り離して移動しても固有か?
- ヘルプテキストは
aria-describedbyで接続されており、ラベルに押し込まれていないか? - 装飾アイコンは支援技術から隠されているか?
- 誰かがブラウザー開発者ツールで計算されたアクセシビリティ名を確認したか?
- 重要なフローについて、少なくとも 1 回は実際のスクリーンリーダーで確認したか?
このチェックリストは、ほとんどのラベル問題がユーザーの問題になる前に捕まえます。
良い ARIA の静かな規律
良い ARIA の仕事は、めったに劇的ではありません。ほとんどは抑制です。
本物のボタンを使う。本物のラベルを使う。表示名とアクセシブルな名前を揃える。より良い表示上の情報源がない場合にだけ aria-label を追加する。ページにすでに適切なテキストがある場合は aria-labelledby を使う。補足的な指示やエラーには aria-describedby を使う。
Web プラットフォームは、私たちがそれを直接使うとき、多くのものを無料で提供してくれます。ARIA は、その隙間を埋めるためにあります。技術とは、実際に隙間があるのはいつかを見極めることです。