ウェブアクセシビリティについてフロントエンドエンジニアが身につけておく2つの知識

## はじめに
「ウェブアクセシビリティとは」を簡単に理解し、
フロントエンドエンジニアが身につけておくべき2つの知識を学ぶ。

2つの知識
- 暗黙のセマンティックスを理解し、必要に応じてrole属性、aria属性を記述する
- aria属性とrole属性の実装方法



##目次
- ウェブアクセシビリティとは
- WAI-ARIAについて
- 暗黙のARIAセマンティックスを理解する
- role属性
- aria属性



## ウェブアクセシビリティとは
ウェブアクセシビリティとは、**ウェブページにある情報や機能の利用しやすさ**を意味する。
健常者はもちろん高齢者や障害者など心身の機能に制約のある人でも、年齢的・身体的条件に関わらず、誰もが利用できる配慮が必要。

**アクセシビリティの高いサイト**の基準として、
国際規格であるウェブ・コンテンツ・アクセシビリティ・ガイドライン（WCAG）2.0の達成基準に取り組み、アクセシビリティ品質を満たすように制作する。
達成基準にはA、AA、AAAがある。
Aは最低限のレベル。
AAは公的機関に求められるレベル。
AAAは理想論的なところを含む。
基本的にはAAに準拠と考える。

※ WCAG2.0の達成基準と達成方法は[こちら](https://waic.jp/docs/UNDERSTANDING-WCAG20/understanding-techniques.html)

※ WCAGの読み方はウィーケグ。
以前大阪で行われた「これから取り組むウェブアクセシビリティ」のセミナーで登壇されたウェブアクセシビリティ基盤委員会の方がこの発音だと伝えてた。
ネットで調べるとダブリュシーエーシーと出てくるのでどちらも正解。

参考：
https://waic.jp/knowledge/accessibility/
https://waic.jp/docs/WCAG20/Overview.html
https://waic.jp/docs/UNDERSTANDING-WCAG20/understanding-techniques.html


## WAI-ARIAについて
W3C（ダブリュースリーシー）によって定められた仕様。
`role属性`や`aria-*属性`を用いて、ブラウザーや支援技術が認識できるさらなる意味論を追加し、ユーザーの理解を助ける技術。
`aria-*属性`、`role属性`はHTMLを補うために追加する属性。ただし、HTMLの要素を正しく使うことを前提に利用する。

※ W3C・・・インターネット上で使用される各種技術を仕様化したドキュメント
※ WAI-ARIAの読み方・・・ウェイ-アリア

## 暗黙のARIAセマンティックスを理解する
`role属性`や`aria-*属性`はコンテンツの役割を正確にブラウザに伝えることができる。
暗黙のARIAセマンティックスと一致する`role属性`または`aria-*属性`の設定は不要（設定自体推奨されない）。
このプロパティが既にブラウザーで設定されている。
タグによって利用できないrole属性があるので注意が必要。
header、footerなどのように子孫要素によって暗黙のARIAセマンティックスが変わるタグもある。


| HTML feature | 暗黙のARIAセマンティックス | 使用できるrole |
|:-----------|:------------:|:------------|
| hrefをもつa | role=link | button, checkbox, menuitem, menuitemcheckbox, menuitemradio, option, radio, switch, tabまたはtreeitem |
| hrefをもつarea | role=link | なし |
| article | role=article | feed, presentation, none, document, application, mainまたはregion. |
| aside | role=complementary | feed, note, presentation, none, regionまたはsearch. |
| body | role=document | なし |
| button | role=button | checkbox, link,menuitem, menuitemcheckbox, menuitemradio, option, radio, switchまたはtab.|
| datalist | role=listbox | なし |
| dd |  role=definition | なし |
| dfn | role=term | すべてのrole |
| detaild | role=group | なし |
| div | 対応するロールなし | すべてのrole |
| dt | role=term | listitem |
| fieldset | role=group | none, presentationまたはradiogroup. |
| figure | role=figure | なし |
| footer | article, aside, main, navもしくはsection要素の子孫でない、またはrole=article, complementary, main, navigationもしくはregionをもつ要素でない場合、role=contentinfo。そうでなければ、対応するロールなし。 | group, noneまたはpresentation |
| form | form要素がアクセシブルな名前を持つ場合、role=form。そうでなければ、対応するロールなし。 | search, noneまたはpresentation |
| h1 - h6 | aria-level = 正の整数をもつ、role=heading | none, presentationまたはtab. |
| header | article, aside, main, navもしくはsection要素の子孫でない、またはrole=article, complementary, main, navigationもしくはregionをもつ要素でない場合、role=banner。そうでなければ、対応するロールなし。 | group, noneまたはpresentation |
| hr | role=separator | groupまたはpresentation |
| alt="テキスト"をもつimg | role=img | button, checkbox, link, menuitem, menuitemcheckbox, menuitemradio, option, progressbar, scrollbar, separator, slider, switch, tabまたはtreeitem |
| alt=""をもつimg | 対応するロールなし | groupまたはpresentation |
| input type=button | role=button | link, menuitem, menuitemcheckbox, menuitemradio, option, radio, switchまたはtab。 |
| input type=checkbox | role=checkbox | button（aria-pressedとともに使用される場合）, menuitemcheckbox, optionまたはswitch。 |
| input type=image | role=button | link, menuitem, menuitemcheckbox, menuitemradio, radioまたはswitch。 |
| input type=radio | role=radio |  |
| input type=range | role=slider |  |
| input type=range | role=slider | なし |
| input type=reset | role=button | なし |
| list属性のないinput type=search | role=searchbox | なし |
| input type=submit | role=button | なし |
| list属性のないinput type=tel | role=textbox | なし |
| list属性のないinput type=text | role=textbox | combobox, searchboxまたはspinbutton。 |
| list>属性をもつinput type=text, search, tel, url,またはemail | role=combobox | なし |
| list属性のないinput type=url | role=textbox | なし |
| 親がol, ulまたはmenuであるli要素 | role=listitem | menuitem, menuitemcheckbox, menuitemradio, option, none, presentation, radio, separator, tabまたはtreeitem |
| hrefをもつlink要素 | role=link | なし |
| main | role=main | なし |
| math | role=math | なし |
| menu | role=list | directory, group, listbox, menu, menubar, none, presentation, radiogroup, tablist, toolbarまたはtree |
| nav | role=navigation | なし |
| ol | role=list | directory, group, listbox, menu, menubar, none, presentation, radiogroup, tablist, toolbarまたはtree |
| optgroup | role=group | なし |
| オプションリストで存在するまたはdatalist要素で提案を表すoption要素 | role=option | なし |
| output | role=status | すべてのrole |
| progress | role=progressbar | なし |
| select（multiple属性をもたず、かつ1より大きい値を持つsize属性がない） | role=combobox | menu |
| select（multiple属性、または1より大きい値を持つsize属性をもつ） | role=listbox | なし |
| summary | role=button | なし |
| table | role=table | すべてのrole |
| tbody | role=rowgroup | すべてのrole |
| textarea | role=textbox | なし |
| tfoot | role=rowgroup | すべてのrole |
| thead | role=rowgroup | すべてのrole |
| td | table要素の子孫の場合のrole=cell | すべてのrole |
| th | role=columnheaderまたはrowheader | すべてのrole |
| tr | role=row、role=gridまたはtreegridをもつtable要素の子のときに明示的に宣言できる | すべてのrole |
| ul | role=list | directory, group, listbox, menu, menubar, none, presentation, radiogroup, tablist, toolbarまたはtree |
| disabled属性をもつ要素 | aria-disabled="true" |  |
| placeholder属性をもつ要素 | aria-placeholder="" |  |
| required属性をもつ要素 | aria-required="true" |  |
| readonly属性をもつ要素 | aria-readonly="true" |  |
| hidden属性をもつ要素 | aria-hidden="true" |  |
| 制約の検証のための候補であるが、その制約を満たさない要素 | aria-invalid="true" |  |
| contenteditable属性をもつ要素委 | aria-readonly="false" |  |

参考：
https://momdo.github.io/html-aria/#document-conformance-requirements-for-use-of-aria-attributes-in-html

### role属性
role属性は、タグの意味を伝えるもの。
ただし、HTMLの要素を正しく使うことを前提に、
**HTMLを補うため**にrole属性を使う。

role属性の利用シーン参考。

```html:
/* メニュー */
<ul role="menu">
  <li role="menuitem">New</li>
  <li role="menuitem">Open</li>
  <li role="menuitem">Save</li>
  <li role="menuitem">Close</li>
</ul>

/* ナビ */
<ul role="navigation">
  <li><a href="/">Home</a></li>
  <li><a href="/about">About</a></li>
  <li><a href="/contact">Contact</a></li>
</ul>

/* アラート */
<div class="alert" role="alert">
  入力にエラーがあります。
</div>

/* aにトリガー機能を持たせる */
<a class="btn btn-next" href="#" role="button">Next</a>

/* ボタングループ */
<div class="btn-group" role="group">
  <button type="button" class="btn">Left</button>
  <button type="button" class="btn">Middle</button>
  <button type="button" class="btn">Right</button>
</div>

/* タブの実装*/
<ul role="tablist">
  <li>パネル1</li>
  <li>パネル2</li>
  <li>パネル3</li>
</ul>
<div role="tabpanel">パネル1の内容</div>
<div role="tabpanel">パネル2の内容</div>
<div role="tabpanel">パネル3の内容</div>

/* ツリー */
<ul role="tree">
  <li role="treeitem">Birds</li>
  <li role="treeitem">Cats
    <ul role="group">
      <li role="treeitem">Siamese</li>
      <li role="treeitem">Tabby</li>
    </ul>
  </li>
  <li role="treeitem">Dogs</li>
</ul>

```

参考：
https://getbootstrap.com/docs/4.4/getting-started/introduction/
https://riptutorial.com/html/topic/2734/aria#related-examples


### aria属性
aria属性の利用シーン参考。

#### aria-controls、aria-selected、aria-hidden
**aria-controls**・・・コンテンツまたは存在が現在の要素によって制御される要素を識別する。
**aria-selected**・・・さまざまなウィジェットの現在の"selected"ステートを示す。
**aria-hidden**・・・要素がアクセシビリティAPIに公開されているかどうかを示す。trueは隠される。


```html:
/* タブ */
<ul role="tablist">
  <li aria-controls="panel1" aria-selected="false">パネル1</li>
  <li aria-controls="panel2" aria-selected="true">パネル2</li>
  <li aria-controls="panel3" aria-selected="false">パネル3</li>
</ul>
/* タブコンテンツ */
<div id="panel1" role="tabpanel" aria-hidden="true">パネル1の内容</div>
<div id="panel2" role="tabpanel" aria-hidden="false">パネル2の内容</div>
<div id="panel3" role="tabpanel" aria-hidden="true">パネル3の内容</div>
```

参考：
https://ics.media/entry/17107/


#### aria-label、aria-labelledby、aria-expanded
**aria-label**・・・現在の要素を分類する文字列の値を定義する。
**aria-labelledby**・・・aria-labelと目的は同じ。
**aria-expanded**・・・現在展開されるまたは折りたたまれるかどうかを示す。

```html:
<button class="js-toggle" type="button" aria-controls="toggle" aria-expanded="false" aria-label="ナビゲーションの開閉ボタン"></button>
<div id="toggle" aria-hidden="true" aria-labelledby="toggleTitle">
  <h2 id="toggleTitle">ドロワータイトル</h2>
  /* toggleコンテンツ */
</div>

/* aria-labelledbyの使い方 その2 */
<div id="billing">請求書</div>
<div>
  <div id="name">名前</div>
  <input type="text" aria-labelledby="billing name">
</div>
```

参考：
https://momdo.github.io/wai-aria-1.1/
https://momdo.github.io/wai-aria-1.1/#aria-expanded
https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/ARIA_Techniques/Using_the_aria-labelledby_attribute


#### aria-current
**aria-current**・・・コンテナまたは関連要素のセット内の現在の項目を表す要素を示す。

```html:
<nav aria-label="breadcrumb">
  <ol class="breadcrumb">
    <li class="breadcrumb-item active" aria-current="page">Home</li>
  </ol>
</nav>
```

■ 値
page  ページのセット内の現在のページを表す。
step  プロセス内の現在のステップを表す。
location  環境またはコンテキスト内の現在位置を表す。
date  日付のコレクション内の現在の日付を表す。
time  時間のセット内の現在の時刻を表す。
true  セット内の現在の項目を表す。
false （デフォルト） セット内の現在の項目を表わさない。

参考：
https://getbootstrap.com/docs/4.4/components/breadcrumb/


## まとめ
正しくコーディングしていれば暗黙のセマンティックスにより最低限のコーディングができているが、
aria属性とrole属性を用いることで、より正確にタグの意味や状態を伝える事ができる。