フロントエンドコーディングでやっておきたいアクセシビリティ対策

Web の進化により、フロントエンドコーディングはデザインを再現するだけでは済まなくなりました。

「ふぅ～。デザイン通りにコーディングしてやったぜぇ～:smirk:」
では終われません！

デザインを再現する以外にも注力することがいっぱい増えました…:persevere:

というわけで、フロントエンドコーディングでやっておきたい**アクセシビリティ対策**をWCAG2.1の4つの原則に分類し、まとめてみました！

## WCAG

対策の前に、WCAGについて簡単に説明します。

WCAG とは「Web Content Accessibility Guidelines」の略称で、ウェブコンテンツのアクセシビリティに関するガイドラインです。
Web技術の標準化を推進する W3C（World Wide Web Consortium）が策定しています。

### 勧告プロセス

W3C が作成する技術文書は、いくつかの段階を経て、最終的に「勧告」という段階へと進みます。
「勧告」までのプロセスは以下となります。

1. 初期草案（First Public Working Draft）
2. 作業草案、または単に草案（Working Draft）
3. 勧告候補（Candidate Recommendation）
4. 勧告案（Proposed Recommendation）
5. 勧告（Recommendation）

https://www.w3.org/2018/Process-20180201/#recs-and-notes

### バージョン履歴

:::note info
2023年10月5日に **2.2** が「勧告」となりました。
:::

#### WCAG 1.0

**1999年5月 勧告**

14のガイドライン、65項目のチェックポイントによって構成されています。
各ガイドラインはチェックポイントが設けられ、3つの優先度に分類されていました。

* 優先度1：Web開発者が満たさなければならないもの（must）
* 優先度2：Web開発者が満たすべきもの（should）
* 優先度3：Web開発者が取り組んでもよいもの（may）

https://www.w3.org/TR/WCAG10/

#### WCAG 2.0

**2008年12月 勧告**

4つの原則、12のガイドラインによって構成されています。
各ガイドラインには検査可能な計61種類の達成基準が設けられています。
WCAG 1.0に存在した「優先度」は廃止され、適合レベル (レベルA・レベルAA・レベルAAA) のみを用いて達成基準を分類する方針へ転換しました。

https://www.w3.org/TR/WCAG20/

https://waic.jp/translations/WCAG20/Overview.html

#### WCAG 2.1

**2018年6月 勧告**

対応が不十分とされていた、以下項目への強化を目的に策定されました。

* スマートフォンやタブレット端末をはじめとしたモバイル対応
* 弱視（ロービジョン）
* 認知・学習障害への対応

WCAG 2.0から17種類の達成基準が追加され、計78種類の達成基準が設けられました。

https://www.w3.org/TR/WCAG21/

https://waic.jp/translations/WCAG21/

#### WCAG 2.2

**2023年10月5日 勧告**

認知障害や学習障害のあるユーザー、弱視のユーザー、モバイルデバイスを利用するユーザーへの対応が強化されています。
新たに4つのガイドラインに関して9つの達成基準が追加されました。

* ガイドライン 2.4 ナビゲーション可能
  * 2.4.11 隠されないフォーカス（最低限）（適合レベルAA）
  * 2.4.12 隠されないフォーカス（高度）（適合レベルAAA）
  * 2.4.13 フォーカスの外観（適合レベルAAA）
* ガイドライン 2.5 入力モダリティ
  * 2.5.7 ドラッグ動作（適合レベルAA）
  * 2.5.8 ターゲットのサイズ（最小限）（適合レベルAA）
* ガイドライン 3.2 予測可能
  * 3.2.6 一貫したヘルプ（適合レベルA）
* ガイドライン 3.3 入力支援
  * 3.3.7 冗長な入力（適合レベルA）
  * 3.3.8 アクセシブルな認証（適合レベルAA）
  * 3.3.9 アクセシブルな認証（高度）（適合レベルAAA）

https://www.w3.org/TR/WCAG22/

#### WCAG 3.0

**2023年7月24日 草案**（2023年9月26日現在）

さまざまな障害を持つ人々にとって、ウェブコンテンツとアプリケーションをアクセシブルなものにすることを目的に作成されています。

https://www.w3.org/TR/wcag-3.0/

### 4つの原則

<dl>
  <dt>1. 知覚可能</dt>
  <dd>情報やUIがあることが知覚できる</dd>
  <dt>2. 操作可能</dt>
  <dd>UIやナビゲーションが操作できる</dd>
  <dt>3. 理解可能</dt>
  <dd>情報やUIの操作が理解できる</dd>
  <dt>4. 堅牢</dt>
  <dd>標準仕様にのっとって実装し、互換性をもたせる</dd>
</dl>

### ガイドライン

4つの原則の中には個別のガイドラインが設けられていて、ウェブコンテンツを制作する際の具体的な指針を表しています。

### 達成基準と適合レベル

個別のガイドラインには達成基準が設けられていて、具体的にどのような項目に取り組むべきかについて定められています。
達成基準にはアクセシビリティの高さに応じて3段階の適合レベル (レベルA・レベルAA・レベルAAA) が割り振られています。

<dl>
  <dt>レベルA</dt>
  <dd>最低限のレベル。<br>支援技術を用いればWebサイトにアクセス可能になる場合が多い。</dd>
  <dt>レベルAA</dt>
  <dd>支援技術なしでもWebサイトにアクセス可能になる場合が多い。</dd>
  <dt>レベルAAA</dt>
  <dd>支さらにWebサイトにアクセスしやすくなる。<br>コンテンツや機能によっては、達成が難しいものもある。</dd>
</dl>

## 1. 知覚可能

### 表示の向きを固定しない（レベルAA）

https://waic.jp/translations/WCAG21/Understanding/orientation.html

:::note info
ヘッダーやフッターを固定表示していると、画面を横にした時に画面を覆ってしまいます。狭い画面サイズでは固定表示を解除するように、メディアクエリーでスタイルを設定しておきます。
:::

```css:CSS
.header {
  position: fixed;
}
/* 拡大した時に固定を解除 */
@media (max-height: 30rem) {
  .header {
    position: static;
  }
}
```

### 配色のコントラスト（レベルAA）

https://waic.jp/translations/WCAG21/Understanding/contrast-minimum.html

:::note info
テキストと背景の間に充分なコントラスト比を確保し、テキストの視認性を上げるだけでなく、中度のロービジョンの人がテキストを読めるようにします。
:::

コントラストの比率は文字の大きさによって変わります。

|文字サイズ|コントラスト比|
|:-|:-|
|18.5px以上の太字（14pt相当）<br>24px以上（18pt相当）|3:1以上|
|それ以外|4.5:1以上|

:::note warn
以下の場合は例外となります。

* アクティブではない状態のUIコンポーネント（押せない状態のボタンなど）
* 装飾のために用いられている文字（何も情報を伝えていない文字）
* 写真の中に写っている文字
* ロゴタイプとして使用されている文字
:::

コントラスト比を確認するのは以下サイトが便利です。

https://colorable.jxnblk.com/

ブラウザのデベロッパーツールでも確認可能です。
要素のスタイルの `color` をクリックすると背景色とのコントラスト比が表示されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492675/9714ef95-8262-25aa-f740-04ba5a13141a.png" width="1000" height="1150" decoding="async" loading="lazy">

## 2. 操作可能

### フォーカストラップ（レベルA）

https://waic.jp/translations/WCAG21/Understanding/no-keyboard-trap.html

:::note info
ハンバーガーメニューや、モーダルなどのオーバーレイコンテンツの表示時に、フォーカスをコンテンツ内で循環できるようにします（フォーカストラップ）。
:::

focus-trap というパッケージを利用すると簡単に実装できます。

https://www.npmjs.com/package/focus-trap

また、オーバーレイコンテンツ表示時に、背景側のコンテンツ要素に `aria-hidden="true"` を設定します。
これにより、不意にスクリーンリーダーでアクセスされてしまうのを防ぐことができます。
aria-hidden というパッケージを利用すると簡単に実装できます。

https://www.npmjs.com/package/aria-hidden

focus-trap と aria-hidden を利用したデモを作成してみました:smiley:

<p class="codepen" data-height="500" data-default-tab="result" data-slug-hash="PoxOZNo" data-user="taqumo" style="height: 500px; box-sizing: border-box; display: flex; align-items: center; justify-content: center; border: 2px solid; margin: 1em 0; padding: 1em;">
  <span>See the Pen <a href="https://codepen.io/taqumo/pen/PoxOZNo">
  Focus Trap Demo</a> by Takuya Mori (<a href="https://codepen.io/taqumo">@taqumo</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### 停止ボタンの設置（レベルA）

https://waic.jp/translations/WCAG21/Understanding/pause-stop-hide.html

:::note info
スライドショーなど、自動で切り替わるコンテンツには、他のコンテンツ操作や閲覧の妨げにならないよう、停止ボタンを設置します。
:::

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/492675/dcd7ca93-4b58-a951-e568-8f1419c261d0.png" width="1000" height="600" decoding="async" loading="lazy">

### アニメーションの無効化（レベルAAA）

https://waic.jp/translations/WCAG21/Understanding/animation-from-interactions.html

:::note info
ユーザーがOSの設定でアニメーションを無効化・削減している場合は、アニメーションさせないようにします。
:::

CSS のメディア特性 `prefers-reduced-motion` を利用して、アニメーションを無効化する設定をしておきます。

```css:CSS
@media (prefers-reduced-motion: reduce) {
  *,
  ::before,
  ::after {
    background-attachment: initial !important;
    transition-delay: 0s !important;
    transition-duration: 1ms !important;
    animation-duration: 1ms !important;
    animation-delay: -1ms !important;
    animation-iteration-count: 1 !important;
    scroll-behavior: auto !important;
  }
}
```

### スキップリンク（レベルA）

https://waic.jp/translations/WCAG21/Understanding/bypass-blocks.html

:::note info
スクリーンリーダー、キーボード操作のユーザーがすぐにメインコンテンツにアクセスできるようにします。
:::

ページの先頭にメインコンテンツへのアンカーリンクを設置しておきます。
デザイン上、表示しておきたくない場合はフォーカス時に表示されるようにしておきます。

```html:HTML
<body>
  <header>
    <p class="skip"><a href="#main">本文へ移動</a></p>
  </header>
  <main id="main">
    <!-- メインコンテンツ -->
  </main>
</body>
```

```css:CSS
/*
 * スクリーンリーダーを除いて非表示（フォーカス時には表示）
 * Bootstrap5 の visually-hidden-focusable を利用
*/
.skip:not(:focus, :focus-within) {
  position: absolute !important;
  width: 1px !important;
  height: 1px !important;
  padding: 0 !important;
  margin: -1px !important;
  overflow: hidden !important;
  clip: rect(0, 0, 0, 0) !important;
  white-space: nowrap !important;
  border: 0 !important;
}
```

### フォーカス時にアウトラインを表示する（レベルAA）

https://waic.jp/translations/WCAG21/Understanding/focus-visible.html

:::note info
キーボード操作を可能にするために、フォーカス時にアウトラインが表示されるようにします。
:::

ボタンなどのフォーカス可能な要素をクリックした時に表示されるアウトラインが格好悪いから消したい！
という理由で、`outline: none;` を設定することが多いと思います。

しかし、このままだとキーボード操作時にアウトラインが表示されず、フォーカスの場所がわかりません。
フォーカス可能な要素は、フォーカス時にアウトラインを表示するように `:focus-visible` の設定をしておきます。

```css:CSS
a,
button,
input,
select,
textarea,
summary {
  outline: none;
}
/* フォーカス時にアウトラインを表示させる */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: 2px solid red;
}
```

## 4. 堅牢性

### ボタンは `<button>`（レベルA）

https://waic.jp/translations/WCAG21/Understanding/name-role-value.html

:::note info
ボタンの役割をする要素は `button` 要素でマークアップします。
:::

`button` 要素を利用すると以下のメリットがあります。

* `tab` でフォーカスが当たる
* フォーカスした状態で `enter` または `space` を押すと、clickイベントが発火する
* スクリーンリーダーで「ボタン」だとわかるように読み上げられる

:::note warn
`button` 要素の `type` 属性の初期値は `type="submit"` で、フォームの送信ボタンとなります。汎用ボタンとして利用する場合は `type="button"` の指定が必要です。
:::

```html:HTML
<!-- NG -->
<div>ボタン</div>
<!-- OK -->
<button type="button">ボタン</button>
```

## 関連記事

https://qiita.com/taqumo/items/3660b04400c28c5c2aa5

https://qiita.com/taqumo/items/0c7116517bb2b44b2939

https://qiita.com/taqumo/items/76a47a588b896e3c9840