WAI-ARIA学習

# WAI-ARIAとは

WAI-ARIA（Web Accessibility Initiative - Accessible Rich Internet Applications Suite）は、Webアプリケーションや動的なWebサイトのアクセシビリティを高めるために、World Wide Web Consortium（W3C）のWeb Accessibility Initiative（WAI）によって開発された技術仕様のことを指す。

WAI-ARIAは、「ウェイエリア」または「ワイエリア」と読まれ、アクセシビリティ向上の為のガイドラインとしての役割を果たす。

ここでの「アクセシビリティ」とは、全ての人が利用しやすい、便利な状態のことを指す。アクセシビリティは製品やサービスの価値・評価の良し悪しに影響を与える。

「Rich」とあるように、近年の「リッチ」な動的なWebサイトやWebアプリケーションは、HTML・CSSのみではアクセシビリティの要件を満たすことが困難となってきている。特に、動的に変化するコンテンツは、マウスを使用できない人や視覚情報を持たない人にとって扱いづらい場合がある。このような場合、サービスの品質向上のためには、アクセシビリティの確保・向上が課題となる。

しかし、アクセシビリティを高める為の支援機能は既に存在している。例えば、テキスト情報の音声による読み上げや、文字の拡大縮小機能など。

WAI-ARIAは、これら支援機能に対して、適切に情報を伝えることによって、支援機能が効果的に働くことを目指している。

WAI-ARIAに関する情報の発信源は、WAI-ARIAの仕様書の他に、ARIA in HTML、Using ARIA、WAI-ARIA Authoring Practices、Core Accessibility API Mappings（core-aam）、HTML Accessibility API Mappings、Accessible Name and Description Computation などがある。

## WAIとは

+ *Web Accessibility Initiative*
+ Webアクセシビリティの推進を目的とするW3Cの内部組織

# WAI-ARIA attribute（ARIA属性）
WAI-ARIA では、HTML要素で使用できる属性が定義されていて、これを**WAI-ARIA attribute**（または**ARIA属性**）という。グローバル属性のように、全てのHTML要素に対して使用することができるが、`class`や`id`のように汎用的に使用するのではなく、それぞれの要素に応じて適切に使用する必要がある。

HTML は W3C によって仕様が策定され、ARIA属性は WAI によって仕様が策定されるため、HTMLで使用できる属性でありながら、HTML仕様とは別の文書で定義されている。WAI-ARIA属性は、HTMLの標準属性とは異なり、アクセシビリティに関連する情報を提供するために導入された。

**役割**（**role**）、**状態**（**state**）、**プロパティ**（**property**）の3つの主要なコンセプトがある。

ホスト言語（HTML）に対して、アクセシビリティを向上させるための追加情報を付与する役割がある。WAI-ARIA属性は、視覚的に表示される要素だけでなく、スクリーンリーダーや支援技術によって利用される要素にもアクセシビリティ情報を提供する。これにより、障害を持つユーザーがウェブコンテンツを理解しやすくなり、操作しやすくなる。

## 役割（Role）

HTML要素の**役割**を表す。`role`属性を使用することで役割を表現する。

```html
<div role=" ">hello</div>
```

特定のHTML要素には、あらかじめ暗黙的に`role`属性が定義されているものもあり、これを **implicit native role** と言う。

暗黙的な`role`属性を持つHTML要素に対して、明示的に`role`属性を指定することは冗長的であり、避けるべきとされる。

また、暗黙的な`role`属性を、別の値で上書きするようなこともできるが、互換性のない上書きはブラウザによって無視される。

`role`属性に、空白区切りで値を複数指定した場合、ブラウザは先頭の値から解釈を進め、適用可能なものが見つかった時点で即採用して解釈処理を終え、それ以降の値は無視する。

または適用できない値が設定されている場合も、ブラウザによって無視される。

### 分類

`role`属性はいくつかのカテゴリーに分類されている。

| カテゴリー | `role`属性値 |
|:-:|:-:|
| Abstract Roles | `command`, `input`, `range`, `section`, `select`, `widget`, `window`
| Widget Roles | `button`, `checkbox`, `gridcell`, `link`,  `menuitem`, `menuitemcheckbox`, `menuitemradio`, `option`, `progressbar`, `radio`, `scrollbar`, `searchbox`, `separator (when focusable)`, `slider`, `spinbutton`, `switch`, `tab`, `tabpanel`, `textbox`, `treeitem` <br>以下はコンテナとしての役割を持つもの<br> `combobox`, `grid`, `listbox`, `menu`, `menubar`, `radiogroup`, `tablist`, `tree`, `treegrid` |
| Document Structure Roles | `application`, `article`, `cell`, `columnheader`, `definition`, `directory`, `document`, `feed`, `figure`, `group`, `heading`, `img`, `list`, `listitem`, `math`, `none`, `note`, `presentation`, `row`, `rowgroup`, `rowheader`, `separator (when not focusable)`, `table`, `term`, `toolbar`, `tooltip` |
| Landmark Roles | `banner`, `complementary`, `contentinfo`, `form`, `main`, `navigation`, `region`, `search` |
| Live Region Roles | `alert`, `log`, `marquee`, `status`, `timer` |
| Window Roles | `alertdialog`, `dialog` |

#### Abstract Roles

>`command`, `input`, `range`, `section`, `select`, `widget`, `window`

`role`属性自体を分類するための、概念的なカテゴリー。**実際に属性値としては使用できない**。

`role`属性には「継承」という概念があり、Abstract Rolesの属性値は、`role`属性自体の特徴や役割を表していて、他の`role`属性が継承している。

#### Widget Roles

>`button`, `checkbox`, `gridcell`, `link`,  `menuitem`, `menuitemcheckbox`, `menuitemradio`, `option`, `progressbar`, `radio`, `scrollbar`, `searchbox`, `separator (when focusable)`, `slider`, `spinbutton`, `switch`, `tab`, `tabpanel`, `textbox`, `treeitem` <br>以下はコンテナとしての役割を持つもの<br> `combobox`, `grid`, `listbox`, `menu`, `menubar`, `radiogroup`, `tablist`, `tree`, `treegrid`

対話的な要素やユーザーインタラクションを持つ要素を、ウィジェットの種類によって表す。インタラクティブな要素や、コンポーネント（Widget）を識別するために使用される。

+ `role="button"`は、要素がクリックやタップなどのアクションをトリガーとするユーザーインタラクションを提供することを表す。ユーザーはボタンを選択してアクションを実行することができる。

+ `role="checkbox"`は、オンまたはオフの選択肢を提供する要素を表す。ユーザーはチェックボックスを選択または解除することができる。

+ `role="link"`は、別のページや場所に移動するためのナビゲーション機能を提供する要素であることを表す。ユーザーはリンクをクリックすることで対象の場所に移動することができる。

+ `role="slider"`は、値の範囲を表すための要素であることを表す。ユーザーはスライダーを操作して値を選択することができる。

+ `role="textbox"`は、テキスト入力や編集のための入力フィールドを提供する要素であることを表す。ユーザーはテキストボックスにテキストを入力したり編集したりすることができる。

+ `role="menu"`は、選択肢のリストを表示し、ユーザーがメニューアイテムを選択することができることを表す。

#### Document Structure

>`application`, `article`, `cell`, `columnheader`, `definition`, `directory`, `document`, `feed`, `figure`, `group`, `heading`, `img`, `list`, `listitem`, `math`, `none`, `note`, `presentation`, `row`, `rowgroup`, `rowheader`, `separator (when not focusable)`, `table`, `term`, `toolbar`, `tooltip`

文書の構造を、より詳細に表す。HTMLが元々持つ文書構造に対して、詳細な構造情報を付け加えることでアクセシビリティが向上する。

+ `role="article"`は、独立した記事やコンテンツのセクションを表す。ウェブページ内で特定のテーマやトピックに関連する情報をグループ化するために使用される。

+ `role="directory"`は、ディレクトリやフォルダのコンテンツを表す。通常、階層的なリストやファイルのツリー形式で表示される。

+ `role="list"`は、リストを表す。項目の一覧や目次など、順序や階層関係のあるアイテムを表示するために使用される。

+ `role="row"`は、テーブルの行を表す。テーブル内のデータを構成するために使用される。

+ `role="toolbar"`は、ツールバーを表す。ボタンやアイコンなどのツールを配置するために使用される。


`role="none"`と`role="presentation"`は *implicit native role* を削除するために使用する。ただし、インタラクティブコンテンツの*implicit native role*や、グローバルARIA属性（後述）が明示的に指定されている場合には削除が働かないこともある。インタラクティブコンテンツとは、`<a>`、`<button>`などのユーザーのアクションに対して、動的な反応や変化をする機能を持つ要素。（`tabindex`属性によって、フォーカスが当てられるようになった要素が、インタラクティブコンテンツとなることもある。）


#### Landmark Roles

>`banner`, `complementary`, `contentinfo`, `form`, `main`, `navigation`, `region`, `search`

Webページにおけるランドマーク（目印）を表す。これにより、ページの構造が明確になり、アクセシビリティの支援技術やユーザーが、コンテンツのセクションやエリアを識別しやすくなる。

多用し過ぎに注意する必要がある。

+ `role="banner"`は、ウェブページの先頭に表示されるヘッダーエリアを表す。通常、ロゴやサイト名、主要なナビゲーションが含まる。

+ `role="navigation"`は、サイト内のリンクやメニューの集合体を表す。ユーザーはここから他のページやセクションに移動することができる。

+ `role="main"`は、ウェブページの主要なコンテンツエリアを表す。ページの主要な情報やコンテンツが配置される場所。

+ `role="complementary"`は、メインコンテンツを補完するための情報やコンテンツを表す。サイドバーや関連記事などが含まれることがある。

+ `role="contentinfo"`は、ウェブページの終わり近くに表示されるフッターエリアを表す。著作権情報や連絡先情報などが含まれることがある。

+ `role="search"`は、検索ボックスや検索機能を提供するエリアを表す。ユーザーはここでキーワードを入力して情報を検索できる。

#### Live Region Roles

>`alert`, `log`, `marquee`, `status`, `timer`


動的なコンテンツや状態の変更を監視し、ユーザーにリアルタイムの情報を提供するために使用される。ページ全体をリロードすることなく、一部のコンテンツを動的に変更するような際に、コンテンツが更新されたことをユーザーに通知する領域であることを示す。ユーザーがWebサイトを閲覧中に更新される可能性があるコンテンツ領域に対して設定する。

多用し過ぎに注意する必要がある。

+ `role="alert"`は、ユーザーに即時の重要な情報や警告を伝えるために使用される。例えば、エラーメッセージや重要な通知など。

+ `role="status"`は、ウェブアプリケーションの状態や進捗を示すために使用される。例えば、処理中のメッセージや進行状況の表示など。

+ `role="log"`は、ウェブアプリケーションのログ情報を表示するために使用される。例えば、操作の履歴や更新情報など。

+ `role="marquee"`は、スクロールするテキストや注目を集めるメッセージを表示するために使用される。一定の時間間隔でテキストが表示され、ユーザーの注意を引くことができる。

#### Window Roles

>`alertdialog`, `dialog`

ブラウザや、アプリケーション内のウインドウ、ダイアログボックス、モーダルなどのウィンドウコンポーネントを表す。

+ `role="alertdialog"`は、重要な情報や警告を伝えるモーダルダイアログボックスを表す。ユーザーに対話的な情報を表示し、重要な操作を促す。

+ `role="dialog"`は、モーダルダイアログボックスを表す。ユーザーに対話的な情報や選択肢を提供し、背後のコンテンツとの対話を一時的に中断する。

## 状態（State）・プロパティ（Property）

状態（State）は要素の**状態**を表す。

プロパティ（Property）は、要素の**性質**や**特性**を表す。

どちらも`aria-`から始まる属性を使用する。状態とプロパティの違いは、そこまで明確なものではない。

:::note info
状態、プロパティの変更は、JavaScript で属性値を変更することで行う。
:::

### 分類

| カテゴリー | 属性 |
|:-:|:-:|
| Widget Attribute | `aria-autocomplete`,`aria-checked`,`aria-disabled`,`aria-errormessage`,`aria-expanded`,`aria-haspopup`,`aria-hidden`,`aria-invalid`,`aria-label`,`aria-level`,`aria-modal`,`aria-multiline`,`aria-multiselectable`,`aria-orientation`,`aria-placeholder`,`aria-pressed`,`aria-readonly`,`aria-required`,`aria-selected`,`aria-sort`,`aria-valuemax`,`aria-valuemin`,`aria-valuenow`,`aria-valuetext` |
| Live Region Attributes | `aria-atomic`,`aria-busy`,`aria-live`,`aria-relevant` |
| Drag-and-Drop Attributes | `aria-dropeffect`,`aria-grabbed` |
| Relationship Attributes | `aria-activedescendant`,`aria-colcount`,`aria-colindex`,`aria-colspan`,`aria-controls`,`aria-describedby`,`aria-details`,`aria-errormessage`,`aria-flowto`,`aria-labelledby`,`aria-owns`,`aria-posinset`,`aria-rowcount`,`aria-rowindex`,`aria-rowspan`,`aria-setsize` |

####  Widget Attribute

> `aria-autocomplete`,`aria-checked`,`aria-disabled`,`aria-errormessage`,`aria-expanded`,`aria-haspopup`,`aria-hidden`,`aria-invalid`,`aria-label`,`aria-level`,`aria-modal`,`aria-multiline`,`aria-multiselectable`,`aria-orientation`,`aria-placeholder`,`aria-pressed`,`aria-readonly`,`aria-required`,`aria-selected`,`aria-sort`,`aria-valuemax`,`aria-valuemin`,`aria-valuenow`,`aria-valuetext`

ユーザーからの入力を受け付けたり、アクションに応じて動的に変化する、要素の状態や振る舞いに関わる情報を提供する。

要素の状態とは、例えば入力フィールドの状態、入力エラーの有無などの、要素が現在どのような状態にあるのかといった情報を指す。

要素の振る舞いとは、要素がドラッグ可能であることや、キーモード操作に応答可能であることなどの、要素がどのように振る舞うことができるのかといった情報を指す。

+ `aria-expanded="value"`は、セクションが展開されているかどうかを示す。
属性値には以下の値が指定できる。
`true`：展開された状態
`false`：閉じられた状態

+ `aria-hidden="value"`は、要素がスクリーンリーダーや、アシスト技術に対して公開されているかどうかを示す。
属性値には以下の値が指定できる。
`true`：公開された状態
`false`：非公開である状態
`true`が指定されても、要素の視覚的な表示自体はされる。スクリーンリーダーによって、読み上げられたくない余計な情報を隠すために使用する。

+ `aria-invalid="value"`は、フィールドの入力が無効であるかどうかを示す。
属性値には以下の値が指定できる。
`true`：無効な入力
`false`：有効な入力

+ `aria-pressed="value"`は、ボタンが押された状態であるかどうかを示す。
属性値には以下の値が指定できる。
`true`：押された状態
`false`：押されていない状態

+ `aria-label="value"`は、要素に対して意味のあるテキストラベル情報を提供する。アイコンボタンなどの、視覚的に表示されるテキストを持たない要素などに対して使用する。要素が元々、テキストラベルを持つ場合、指定した値で上書きすることになるが、代替テキストとして使用するのではなく、元々テキストラベルを持たない要素に対してや、元々のテキストラベルでは情報が不十分な場合に使用する。そのため、画像やメディア要素の場合は`alt`属性や`aria-labelledby`属性を使用する。

+ `aria-level="value"`は、見出しや、リストアイテムなどに対して、その要素の階層レベル（ネストの深さ）を示す。コンテンツの階層構造を示すことができる。
属性値には整数を指定することができる。


+ `aria-required="value"`は、フィールドが必須であるかどうかを示す。
属性値には以下の値が指定できる。
`true`：必須フィールド
`false`：任意のフィールド

:::note info
属性値を`true`、`false`で指定するものは状態（state）、
固有の値で指定するものはプロパティ（property）
:::

#### Live Region Attributes

>`aria-atomic`,`aria-busy`,`aria-live`,`aria-relevant`

動的なコンツンツや、要素の状態の変更をリアルタイムで提供する。新しい通知や更新情報、エラーメッセージの表示などが含まれ、これらの変更を監視、通知することで、ユーザーに重要な情報を伝える。

+ `aria-atomic="value"`は、動的なコンテンツの内容が部分的に更新される場合に、更新内容全体を通知するかどうかを指定する。
属性値には以下の値が指定できる。
`true`：部分的な更新を無視して全体を通知する。例えば、表示された時刻が「12:01」から「12:02」に更新された場合、「12:02」を通知する。
`false`：部分的な更新のみを通知する。例えば、表示された時刻が「12:01」から「12:02」に更新された場合、「2」を通知する。

+ `aria-live="value"`は、動的に変更される領域の役割と振る舞いを定義する。
属性値には以下の値が指定できる。
`off`：動的に変更される領域の状態が、更新されないことを示す
`polite`：動的に変更される領域の状態が、ユーザーの操作を妨げない程度に重要であることを示す。例えば、スクリーンリーダーが他の箇所の読み上げを行っている最中に更新がされても、読み上げがひと段落するまでは通知されない。
`assertive`：動的に変更される領域の状態が、ユーザーの操作を優先するほどに重要であることを示す。例えば、スクリーンリーダーが他の箇所の読み上げを行っている最中に更新がされた場合、読み上げを中断して即座に更新が通知される。

+ `aria-relevant="value"`は、動的な領域の内容が変化したときに、どのような情報を通知するかを指定する。
属性値には以下の値が指定できる。
`additions`：新しい要素が追加されたことを通知する
`removals`：要素が削除されたことを通知する
`text`：テキストの変更があったことを通知する
`all`：すべての変更を通知する


#### Drag-and-Drop Attributes

>`aria-dropeffect`,`aria-grabbed`

要素のドラッグやドロップ操作に関連する情報を提供する。ユーザーが要素を移動したり、並び替えたりする際の視覚的なフィードバックや、操作の状態を正確に示すことができる

+ `aria-dropeffect="value"`は、要素に対して行うことができる、ドラッグアンドドロップ操作の種類を指定する。
属性値には以下の値が指定できる。
`none`：要素がドロップ操作を受け付けない
`copy`：要素がドロップされると、コピーされる
`move`：要素がドロップされると、移動する
`link`：要素がドロップされると、リンクを作成する

+ `aria-grabbed="value"`は、要素がドラッグ中であるかどうかを示す。
属性値には以下の値が指定できる。
`true`：ドラッグ中
`false`：ドラッグ中でない

#### Relationship Attributes

>`aria-activedescendant`,`aria-colcount`,`aria-colindex`,`aria-colspan`,`aria-controls`,`aria-describedby`,`aria-details`,`aria-errormessage`,`aria-flowto`,`aria-labelledby`,`aria-owns`,`aria-posinset`,`aria-rowcount`,`aria-rowindex`,`aria-rowspan`,`aria-setsize`

要素間の関係性や、階層によるグループ化を行う。例えば、要素が特定のセクションに属していることを示す属性や、要素間の親子関係を示す属性などが含まれる。


+ `aria-controls="value"`は、その要素と、その要素が制御する（または関連付けられた）別の要素を関連づける。
属性値には、関連する要素の`id`属性値を指定する。
例えば、ボタンが特定のダイアログボックスを制御する場合、ダイアログボックスが持つ`id`値を、ボタンに対して`aria-controls`属性として指定することで、その関係を示すことができる。

+ `aria-describedby="value"`は、要素に関連する補足的な説明や情報を提供する。
属性値には、関連する要素の`id`属性値を指定する。
例えば、`input`要素に対して「〇〇を入力してください」などと表示している`label`要素の`id`を指定することで、スクリーンリーダーが適切に説明箇所を認識して読み上げてくれるようになる。

+ `aria-labelledby="value"`は、その要素と、関連するラベル要素を関連づける。
属性値には、関連する要素の`id`属性値を指定する。
例えば、フォームコントロールが対応するラベルを持つ場合、ラベルが持つ`id`値を、フォームコントロールに対して`aria-labelledby`属性として指定することで、その関係を示すことができる。（`label`要素の`for`属性とは参照の方向が逆。）

+ `aria-owns="value"`は、その要素（親）と、その要素が所有する（または関連付けられた）要素（子）の階層関係（親子関係）を定義する。
属性値には、所有する要素の`id`属性値を指定する。
例えば、メニューボタンが、特定のメニューアイテムを所有している場合、メニューアイテム要素が持つ`id`（複数の場合、スペース区切り）を、メニューボタン要素に対して`aria-owns`属性として指定することで、その階層関係を示すことができる。

## Global States and Properties（グローバルARIA属性）

HTMLのグローバル属性の中には、`aria-`で始まるものが存在し、WAI-ARIAの状態やプロパティと似た役割を果たすものがある。

グローバル属性は、HTML仕様の一部であり、正確にはWAI-ARIAの状態やプロパティに分類されるものではないが、WAI-ARIAのアクセシビリティの原則に基づいて、使用されることがある。

| カテゴリ | 属性 |
|:-:|:-:|
| Global States and Properties | `aria-atomic`,`aria-busy`,`aria-controls`,`aria-current`,`aria-describedby`,`aria-description`,`aria-details`,`aria-disabled`,`aria-dropeffect`,`aria-errormessage`,`aria-flowto`,`aria-grabbed`,`aria-haspopup`,`aria-hidden`,`aria-invalid`,`aria-keyshortcuts`,`aria-label`,`aria-labelledby`,`aria-live`,`aria-owns`,`aria-relevant`,`aria-roledescription` |

+ `aria-current="value"`は、ユーザーが現在どの要素を操作しているのかを明示的に示す。主にナビゲーションやリスト内のアイテム、パンくずリストに対して使用される。
属性値には以下の値が指定できる。以下はトークンと呼ばれる。
`page`：ナビゲーションメニューなどで、要素のリンク先が現在表示しているページであることを示す
`step`：マルチステップフォームや、プログレスバーなどで進行中のプロセス、手順であることを示す
`location`：地図上の場所や、タブパネル内の現在表示されているタブに対して、現在の位置であることを示す
`date`：カレンダーなどで現在の日付であることを示す
`time`：現在の時刻であることを示す

+ `aria-haspopup="value"`は、その要素がポップアップメニューや、ドロップダウンメニューなどのサブメニューを持つことを示す。
属性値には以下の値が指定できる。
`true`：サブメニューを持つ
`false`：サブメニューを持たない

# 気をつけること

+ マウスでのクリックやタップで操作可能なものは、キーボードでも操作可能にする必要がある。

+ できる限り標準のHTMLを優先する。
WAI-ARIA属性は、あくまでも標準のHTMLでは表現できない、補完的なアクセシビリティ情報を伝えるために使用する。
また、すでに標準のHTMLが表現している内容がある場合は、冗長的に同じ内容のWAI-ARIA属性を重複して指定しない。
implicit native role を無理に変更する必要はない。

+ 正確な属性値を使用する
正確で適切な属性値を指定しないと、アクセシビリティ上の問題が発生する。不正確な属性値が指定されるよりも、かえっ使用しない方が良いこともある。

+ 一貫性を保つ
同じ目的で使用される複数の要素に対して、一貫した属性を使用することで、ユーザーは一貫したアクセシビリティ体験を得ることができる。一貫性を保つためには、プロジェクト全体で統一されたガイドラインやパターンを使用する。

# 参考
・<a href="https://amzn.asia/d/a5Zg43H" target="_blank" rel="noopener noreferrer">HTML解体新書-仕様から紐解く本格入門</a>
・<a href="https://www.w3.org/TR/wai-aria/#roles_categorization" target="_blank" rel="noopener noreferrer">Accessible Rich Internet Applications (WAI-ARIA) 1.1</a>
・<a href="https://zenn.dev/yusukehirao/articles/e3512a58df58fd#fnref-4fd6-8" target="_blank" rel="noopener noreferrer">WAI-ARIAを学ぶときに整理しておきたいこと</a>