ARIAロールの解説:HTMLでARIAをいつどのように使うか

ARIA(Accessible Rich Internet Applications)は、開発者に対して、動的で複雑なウェブインターフェースをスクリーンリーダー利用者にもアクセス可能にするための強力なツールキットを提供します。しかし、その誤用は蔓延しており、代償も大きくなっています。このガイドでは、主要なARIAロールのカテゴリをすべて分解して解説し、ARIA使用の黄金律を説明し、さらに具体的なコード例を示すことで、正しく適用できるようにします。

ここに考えさせられる数字があります。WebAIM が上位100万件のウェブサイトのホームページを分析したところ、ARIA 属性を含むページは、ARIA をまったく使っていないページよりも、検出可能なアクセシビリティエラーの平均数が大幅に多いことが分かりました。これは ARIA の使用に反対する主張ではなく、ARIA を正しく使うべきだという主張です。ARIA は現代のアクセシビリティツールキットの中でも最も強力なツールの1つですが、同時に最も誤解されているものの1つでもあります。正しく使えば、障害のある何百万人ものユーザーに向けてサイトを本当に開くことができます。間違った使い方をすれば、彼らの体験を積極的に悪化させてしまいます。

ARIA とは何か、なぜ存在するのか?

ARIA は Accessible Rich Internet Applications(アクセシブルなリッチインターネットアプリケーション)の略です。これは W3C の Web Accessibility Initiative によって定義された HTML 属性のセットであり、開発者がスクリーンリーダー、点字ディスプレイ、音声コントロールソフトウェアなどの支援技術に対して、セマンティックな情報を伝達できるようにするものです。ブラウザがページをレンダリングするとき、DOM(目に見えるもの)とアクセシビリティツリー(支援技術が読み取るもの)という2つの並行した構造を構築します。ARIA 属性を使うと、このアクセシビリティツリーを修正し、カスタムコンポーネントが何であり、どのように振る舞うのかを正確に記述できます。

ARIA の必要性は、実際の問題から生まれました。HTML はドキュメントのために設計されており、アプリケーションのためではありません。ウェブがタブ付きインターフェース、モーダルダイアログ、ドラッグ&ドロップ、ライブデータフィードといったリッチでインタラクティブな体験のためのプラットフォームへと進化したとき、ネイティブの HTML 要素では、それらのコンポーネントが何であり、スクリーンリーダーに対してどのように動作するのかを伝えることができませんでした。ARIA はそのギャップを埋めます。MDN の表現を借りれば、ARIA は「アプリケーションで一般的に使用されるインタラクションやウィジェットを、他に手段がない場合に支援技術へ渡せるように HTML を補完する」ものです。

ARIA は視覚的な見た目を変えません。振る舞いを追加しません。自動的にキーボードサポートを提供することもありません。純粋に、アクセシビリティツリーが支援技術に公開する内容を変更するだけです。これは重要な区別であり、ARIA を近道として使おうとしたときに開発者が犯す多くのエラーの原因になっています。

仕様は W3C によって WAI-ARIA として管理されており、現在のバージョンは 1.2、1.3 が積極的に開発中です。これは、現代のウェブパターン全体にわたるアクセシブルなユーザーインターフェイス要素を記述するための、ロール、ステート、プロパティのオントロジーを提供します。

3つの柱:Roles、States、Properties

ARIA のコードを1行でも書く前に、仕様が提供する3つの異なる構成要素を理解する必要があります。これらは互換ではなく、混同することがエラーの最も一般的な原因の1つです。

Roles は要素が何であるかを定義します。ロールは「今見ているものはどんな種類のものか?」という問いに答えます。例としては、buttondialognavigationtablistprogressbar などがあります。ロールは role 属性で適用します:<div role='button'>。ロールは要素の目的を支援技術に伝え、ユーザーがどのように操作すべきかを理解できるようにします。

States は要素の動的な状態、つまりユーザーがページとやり取りする中で変化するものを表します。aria-expanded 属性は、折りたたみセクションが開いているか閉じているかをスクリーンリーダーに伝えます。aria-checked は、カスタムチェックボックスがチェックされているかどうかを反映します。ステートは JavaScript と同期させなければなりません。決して変化しない静的な aria-expanded='false' は、役に立たないだけでなく、積極的に誤解を招きます。

Properties は、通常はより安定した、要素に関する説明的な情報を提供します。aria-label は、要素にアクセシブルネームを与え、可視テキストを上書きします。aria-labelledby は、そのテキストがラベルとして機能する別の要素を指します。aria-describedby は補足的な説明テキストを関連付けます。aria-required は、そのフォームフィールドが入力必須であることを示します。ステートは頻繁に変化することが期待されますが、プロパティは一度設定したらそのままにしておくことが多いです(例外はありますが)。

Roles は要素が何であるかを定義します。States はその要素が今どのように振る舞っているかを定義します。Properties は追加の説明的なコンテキストを提供します。完全にアクセシブルなカスタムコンポーネントを作るには、この3つが連携して機能する必要があります。

黄金律 ― そしてそれが思っている以上に重要な理由

W3C による ARIA 使用の第一ルールは明確です。必要なセマンティクスと振る舞いがすでに組み込まれているネイティブ HTML 要素や属性が使えるなら、それを使うこと。最初から ARIA に頼ってはいけません。これは「悪い ARIA を使うくらいなら、ARIA を使わない方が良い(no ARIA is better than bad ARIA)」という原則と呼ばれることもあります。このフレーズは、善意ではあるものの誤った ARIA の使い方が持つ非常に現実的な危険性を表しています。

ネイティブ HTML 要素は、暗黙の ARIA セマンティクスを無料で提供してくれます。<button> 要素は、アクセシビリティツリー上ですでにボタンとして公開されています。すでにキーボードフォーカス可能です。すでに Enter と Space の両方のキー押下で発火します。すでにラベルをアナウンスします。<div role='button'> と書いた瞬間、キーボード処理、フォーカス管理、ステート更新など、そのすべての振る舞いを JavaScript で手動で再現する責任を負うことになります。これは理論上の懸念ではありません。カスタムボタンでキーボードサポートを忘れることは、本番環境で最もよく見られ、かつ最も有害な ARIA エラーの1つです。

ARIA が本当に必要になるケースは、いくつかのシナリオに集中する傾向があります。HTML に相当するものが存在しない複雑なウィジェット(カルーセル、オートコンプリート付きコンボボックス、ツリービュー)を構築しているとき。DOM の再構成がコスト的に見合わないレガシーマークアップを是正しているとき。カスタムセマンティクスを公開する必要がある Web コンポーネントを構築しているとき。あるいは、ネイティブ要素に対するブラウザと支援技術のサポートが十分に一貫しておらず、実際には ARIA の同等物の方がより信頼性高く動作する場合です。

それ以外のシナリオでは、常にまずセマンティック HTML を優先すべきです。<div role='navigation'> の代わりに <nav> を使う。<div role='main'> の代わりに <main> を使う。<div role='button'> の代わりに <button> を使う。ネイティブ要素の方が堅牢で、サポートも良く、必要なメンテナンスもはるかに少なくて済みます。

主要な ARIA ロールカテゴリのツアー

WAI-ARIA 仕様はロールをいくつかのカテゴリに整理しています。これらのカテゴリを理解することで、どのロールをいつ使うべきかが分かるようになります。

Landmark Roles

ランドマークロールはページの主要な領域をマークし、スクリーンリーダーユーザーがキーボードショートカットを使って重要なセクションへ直接ジャンプできるようにします。最も一般的に使われるランドマークロールは、bannernavigationmaincomplementarycontentinfosearchform です。これらはすべて、<header><nav><main><aside><footer> など、ネイティブ HTML の直接の対応要素を持っています。実際には、モダンなセマンティック HTML を使っている場合、ランドマークロールはほとんど常に冗長です。構造上の理由で非セマンティックなマークアップを使わざるを得ないときにのみ追加してください。

<!-- Prefer this -->
<header>
  <nav>...</nav>
</header>
<main>...</main>
<footer>...</footer>

<!-- Use ARIA only when you must use divs -->
<div role='banner'>
  <div role='navigation'>...</div>
</div>
<div role='main'>...</div>
<div role='contentinfo'>...</div>

Widget Roles

ウィジェットロールは、ユーザーが直接操作するインタラクティブなコンポーネントを表します。多くのウィジェットパターンにはネイティブ HTML の同等物が存在しないため、ARIA が最も重要な役割を果たすのはここです。一般的なウィジェットロールには、buttoncheckboxdialogmenumenuitemslidertablisttabtabpaneltooltiptreecombobox などがあります。

ウィジェットロールを使うときは、キーボードインタラクションに対して全面的な責任を負うことになります。WAI-ARIA Authoring Practices Guide(APG)は、すべてのウィジェットタイプについて期待されるキーボードパターンを定義しています。例えば、タブ間の移動には矢印キー、ダイアログを閉じるには Escape、リストボックスの最初と最後の項目にジャンプするには Home と End などです。これらのパターンを実装しないと、コンポーネントは技術的にはラベル付けされていても、キーボードのみのユーザーにとっては実質的に使用不能になります。

<!-- A custom tab interface -->
<div role='tablist' aria-label='Account settings'>
  <button role='tab' aria-selected='true' aria-controls='panel-profile' id='tab-profile'>
    Profile
  </button>
  <button role='tab' aria-selected='false' aria-controls='panel-security' id='tab-security' tabindex='-1'>
    Security
  </button>
</div>
<div role='tabpanel' id='panel-profile' aria-labelledby='tab-profile'>
  <p>Profile settings content</p>
</div>
<div role='tabpanel' id='panel-security' aria-labelledby='tab-security' hidden>
  <p>Security settings content</p>
</div>

Live Region Roles

ライブリージョンは、ARIA の中でも最も実用的な機能の1つです。これにより、支援技術はステータスメッセージ、エラーメッセージ、チャットメッセージ、ローディングインジケーターなどの動的なコンテンツ更新を、画面の変化を見ることができないユーザーにアナウンスできます。ライブリージョンがなければ、フォームを送信したスクリーンリーダーユーザーは、フォーカスが明示的に結果へ移動されない限り、成功したのか失敗したのかを知ることができないかもしれません。

コアとなるライブリージョンロールは、alertstatuslogmarqueetimer です。alert ロールは暗黙的に aria-live='assertive' 設定を持ち、ユーザーを即座に割り込む形でアナウンスします。これはエラーや緊急の警告に適しています。status ロールは aria-live='polite' を使い、ユーザーが現在の作業を終えるのを待ってからアナウンスします。これは成功メッセージや進捗インジケーターに最適です。

<!-- Polite status message for non-urgent feedback -->
<div role='status' aria-live='polite' aria-atomic='true'>
  <!-- Dynamically inject text here with JavaScript -->
</div>

<!-- Assertive alert for errors that demand immediate attention -->
<div role='alert'>
  Please correct the errors below before submitting.
</div>

ライブリージョンの鍵は、動的コンテンツが挿入される前に、そのコンテナが DOM に存在していなければならないという点です。ライブリージョンを作成すると同時に中身も詰め込むと、スクリーンリーダーに見逃されることがよくあります。ページロード時にコンテナを構築し、イベント発生時に JavaScript で中身を挿入してください。

Document Structure Roles

articlelistlistitemtablerowcellfigureheading などのドキュメント構造ロールは、コンテンツの構造的な構成を表します。これらのほとんどは現在、ネイティブ HTML 要素によって置き換えられており、MDN はドキュメント構造ロールの大半について「ブラウザが同じ意味を持つセマンティック HTML 要素をサポートするようになったため、もはや使用すべきではない」と述べています。主な例外は、ネイティブ HTML 要素が利用できないカスタムレンダリング環境、Web コンポーネント、SVG ベースのコンテンツを扱っている場合です。

開発者が知っておくべき必須の ARIA プロパティ

ロール以外にも、実際のアクセシビリティ対応で頻出する ARIA プロパティがいくつかあります。最もよく使うのは次のものです。

  • aria-label: 可視のテキストラベルがない、または可視テキストだけでは不十分な場合に、要素にアクセシブルネームを提供します。よくあるユースケース:アイコンのみのボタン、可視ラベルのない検索フィールド、モーダルの閉じるボタンなど。aria-label は可視テキストやネイティブラベルを上書きするため、可視テキストを持つ要素に対しては慎重に使用してください。
  • aria-labelledby: アクセシブルネームとして機能するテキストコンテンツを持つ1つ以上の要素を指します。可視コンテンツとテキストが同期し続けるため、複雑なケースでは aria-label より堅牢です。スペース区切りの要素 ID のリストを受け取り、支援技術は参照されたテキストを順番に連結します。
  • aria-describedby: 補足的な説明テキストへのリンクです。名前ではなく、追加のコンテキストを提供します。フォームフィールドとそのエラーメッセージを関連付けたり、ツールチップをそれが説明する要素に関連付けたりするために使います。スクリーンリーダーは通常、要素の名前とロールを読み上げた後にこれをアナウンスします。
  • aria-hidden: 要素をアクセシビリティツリーから完全に除外します。装飾アイコン、重複コンテンツ、スクリーンリーダーユーザーにとってノイズとなる視覚専用の要素にとても有用です。フォーカス可能な要素に aria-hidden='true' を決して適用しないでください。ユーザーはタブでそこに移動できてしまいますが、その要素について何の情報も得られません。
  • aria-expanded: ドロップダウン、アコーディオン、ディスクロージャーウィジェットなどの折りたたみ要素が現在開いているか閉じているかを伝えます。JavaScript で動的にトグルしなければなりません。静的な値は、属性を付けないよりも悪いです。
  • aria-current: 集合の中で現在の項目を示します。最も一般的には、ナビゲーションでアクティブなページリンク(aria-current='page')や、マルチステッププロセスの現在のステップをマークするために使われます。

実際にアクセシビリティを損なうよくある ARIA の誤用

ARIA を含むページは、ARIA を含まないページよりもアクセシビリティエラーが多い傾向があることを踏まえると、何が最もよく問題になるのかを明示しておく価値があります。これはレアケースではなく、本番コードで毎日のように見られるパターンです。

強いネイティブセマンティクスを持つ要素に ARIA ロールを付与すること。 一部の HTML 要素には、仕様で「強いネイティブセマンティクス」と呼ばれるものがあります。これはブラウザに深く組み込まれており、安全に上書きできない意味です。<button><input> に不適切なロールを付与すると、ブラウザが ARIA ロールを完全に無視したり、支援技術を混乱させる矛盾した挙動を生んだりする可能性があります。宣言するロールは、それを付与する要素に対して適切でなければなりません。

ウィジェットロールでキーボードサポートを忘れること。 ARIA の role='button' は、その要素がボタンであることをスクリーンリーダーに伝えますが、その要素をキーボード操作可能にはしません。<div>role='button' を付ける場合、フォーカス可能にするために tabindex='0' を追加し、Enter と Space の両方のキーに対するイベントリスナーを追加しなければなりません。このどれか1つでも欠けると、キーボードのみのユーザーにとって体験が破綻します。

<!-- Incomplete and inaccessible -->
<div role='button' onclick='doSomething()'>Submit</div>

<!-- Correct custom button implementation -->
<div
  role='button'
  tabindex='0'
  onclick='doSomething()'
  onkeydown='if(event.key==="Enter"||event.key===" ")doSomething()'
>Submit</div>

<!-- Or, the right answer: just use a button -->
<button onclick='doSomething()'>Submit</button>

フォーカス可能な要素に aria-hidden を使うこと。 フォーカス可能な要素に aria-hidden='true' を適用すると、その要素はアクセシビリティツリーからは隠されますが、キーボードナビゲーションからは隠されません。キーボードユーザーはタブでそこに移動できてしまいますが、その要素について何の情報も得られず、それが何をするのか知る術がありません。これは WCAG 2.1 の達成基準 4.1.2(名前(Name)、役割(Role)、値(Value))の違反です。

古い ARIA ステート。 UI が変化したときに aria-expandedaria-checkedaria-selected などのステートを更新しないと、スクリーンリーダーユーザーにはインターフェイスの根本的に誤った姿が伝わります。メニューが視覚的には開いているのに、トリガーが依然として aria-expanded='false' と読み上げられるのは、積極的に欺瞞的です。

冗長なロール。 <nav> 要素に role='navigation' を追加したり、<button>role='button' を追加したりしても、何の役にも立ちません。コードを散らかし、場合によっては特定の支援技術の組み合わせを混乱させることもあります。ネイティブセマンティクスを信頼してください。

ARIA と WCAG:その関係を理解する

ARIA は WCAG ではありません。両者は別個の仕様であり、連携して機能します。WCAG(Web Content Accessibility Guidelines)は、アクセシブルなコンテンツに必要な成果、つまり何を達成すべきかを定義します。ARIA はその一部を実現するための技術的な手段、つまりどのように達成するかの一部です。ARIA に最も関連する WCAG の達成基準は 4.1.2:名前(Name)、役割(Role)、値(Value) であり、すべてのユーザーインターフェイスコンポーネントが名前を持ち、その役割を支援技術に公開し、その状態とプロパティをプログラム的に伝達することを求めています。ARIA は、カスタムコンポーネントに対してこの達成基準を満たすための主要なツールの1つです。

ARIA は他のいくつかの達成基準も支援します。ランドマークロールは、スキップナビゲーションを可能にすることで 2.4.1(ブロックの回避)に貢献します。ライブリージョンは、フォーカスを受け取ることなくステータスメッセージがプログラム的に判別可能であることを求める WCAG 2.1 の 4.1.3(ステータスメッセージ)を満たすための適切なツールであることが多いです。aria-labelaria-labelledby を適切に使うことは、2.4.6(見出しおよびラベル)と 1.3.1(情報及び関係性)の達成に役立ちます。

また、WCAG 準拠は法的要件となりつつあることにも注意が必要です。European Accessibility Act は 2025年6月に完全施行され、EU 加盟国全体の幅広い民間セクターのデジタルサービスに対して、アクセシビリティ要件を義務付けました。米国では、ADA はウェブアクセシビリティを含むものとして解釈され続けており、Section 508 に基づく連邦要件は政府および連邦資金を受ける組織に適用されます。ARIA を正しく理解することは、単なるベストプラクティスではなく、コンプライアンス義務の一部になりつつあります。

ARIA 実装のテスト

ARIA の実装が実際に機能しているかどうかを知る唯一の方法は、実際の支援技術でテストすることです。axe、WAVE、Lighthouse のような自動ツールは、必須プロパティの欠如、無効なロール、フォーカス可能要素への aria-hidden の適用といった構造的な違反を検出できますが、スクリーンリーダーがモーダルをユーザーにとって意味のある形でアナウンスしているか、カスタムツリーウィジェットのキーボードナビゲーションが期待されるパターンに従っているかどうかまでは教えてくれません。

手動テストでは、主にカバーすべきスクリーンリーダーは Windows 上の JAWS と NVDA(両者でデスクトップスクリーンリーダー利用の大半を占めます)、そして macOS と iOS 上の VoiceOver です。Android では TalkBack が該当します。スクリーンリーダーとブラウザの組み合わせごとに挙動が異なることがあるため、少なくとも2つの組み合わせでテストすることが強く推奨されます。すべてのインタラクティブな状態をテストしてください。ダイアログを開く、アコーディオンを展開する、オプションを選択する、アラートをトリガーする。視覚ユーザーが同じインターフェイスを見て理解する内容と、アナウンス内容が一致していることを確認します。

カスタムウィジェットをテストするときは、そのウィジェットタイプについて WAI-ARIA Authoring Practices Guide で定義されているキーボードインタラクションモデルを一通り試してください。タブリストが矢印キーに反応しない、ダイアログがフォーカスをトラップしないといった場合、ARIA マークアップが自動監査上どれほど正しく見えても、それは失敗です。

重要なポイントのまとめ

  • 常に ARIA よりセマンティック HTML を優先する。 <button><nav><main><dialog> のようなネイティブ要素は、ARIA を付けた div の同等物よりも堅牢で、必要なコードもはるかに少ない組み込みのアクセシビリティセマンティクスを持っています。ネイティブ HTML が本当に不足している場合にのみ ARIA に頼ってください。
  • ARIA ロールは近道ではなく「約束」だ。 カスタム要素に role='button'role='dialog' を適用することは、そのウィジェットタイプの完全なキーボードインタラクションモデルを実装することを約束する行為です。ロールに見合う振る舞いが伴わないと、混乱と WCAG 違反を生みます。
  • ARIA ステートを UI と同期させ続ける。 aria-expandedaria-checkedaria-selected のような動的属性や、aria-live コンテンツは、UI の変化に合わせて JavaScript で更新しなければなりません。古いステートは積極的に有害であり、ユーザーに誤った情報を伝えます。
  • 動的コンテンツ更新にはライブリージョンを使う。 ページリロードなしで更新されるあらゆるコンテンツ(通知、エラーメッセージ、ローディング状態、チャットフィードなど)は、aria-live リージョンか、alertstatus のような適切なロールを必要とします。そうすることで、スクリーンリーダーユーザーも視覚ユーザーと同じ情報を自動的に受け取れます。
  • 自動ツールだけでなく、実際の支援技術でテストする。 自動スキャナーは構造的な ARIA エラーを検出できますが、実装が一貫性のある使いやすい体験を生み出しているかどうかは検証できません。そのギャップを埋める唯一の方法は、JAWS、NVDA、VoiceOver を使った手動テストです。