スクリーンリーダー対応の備忘録

この記事は、[フラー株式会社 Advent Calendar 2021](https://qiita.com/advent-calendar/2021/fuller-inc)の3日目の記事です。 


kanterburyさんで、[US配列HHKBライクなカーソル操作のショートカットをmacで自作する](https://kanterbury.hatenablog.com/entry/2021/12/02/094700)でした。



直近の開発で、モバイルブラウザでのスクリーンリーダーへの対応をやる機会がありました。
「スクリーンリーダーって何？」状態からやってきてひと段落ついたので、これまでにやってきたことをまとめようと思います。

# 目次
- そもそもスクリーンリーダー、WAI-ARIAとは
- WAI-ARIAを利用した実装を行うために勉強したこと
- どんな感じでスクリーンリーダー対応を行なっていったか
- スクリーンリーダー対応で得た知見

## そもそもスクリーンリーダー、WAI-ARIAとは
スクリーンリーダーはPCやスマホに搭載されている、画面にあるテキストや画像などを読み上げてくれる機能です。
この機能を使用することで、目が不自由な方もキーボードやタッチ操作だけでPCやスマホが利用できるようになります。
（画像はMacのVoiceOverの設定画面です。）
![スクリーンショット 2021-12-03 2.15.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540090/246b880b-298c-012b-403e-bf56dd763cc1.png)

Webページでは普通、 `<button>` 、`<img>` などのHTMLの要素を元に、読み上げの対象の要素が何であるかを判断します。
下記の例はボタンをVoiceOverで読み上げた時の画像です。

```html:sample.html
<button>
  次のページへ
</button>
```

![スクリーンショット 2021-12-03 2.53.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540090/44b96692-ae62-2c64-12a2-be89eddb342e.png)

ただ、見た目をカスタマイズするために、 `<button>` を使わず `<div>` を使って実装するといった場合が出てくると、スクリーンリーダーではボタンと認識できなくなります。
他にも　(^_^) といった顔文字もテキストと認識されてしまうといったケースもあります。

このような状況の時、WAI-ARIAで定義されているHTML属性を利用することで、要素に追加で意味を付与することができます。
下記の例は絵文字に追加で意味を付与した例です。

```html:sample2.html
<p>sample2</p>
<span role="img" aria-label="えがお">
  (^_^)
</span>
```
![スクリーンショット 2021-12-03 3.10.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540090/045f0ac6-d41d-b675-1e27-c4495126898c.png)



## WAI-ARIAを利用した実装を行うために勉強したこと

主にやったことは以下の3点です。
- WAI-ARIA Authoring Practicesで実装例を確認する
- MDNでロール、ステート、プロパティの使い方を確認する
- WCAGでガイドラインの確認

[WAI-ARIA Authoring Practices](https://www.w3.org/TR/wai-aria-practices-1.2/)は、WAI-ARIAで定義されているHTML属性を利用して、アクセシブルなWebアプリを作る方法が紹介されています。

初めはとにかく時間がなかったということと、いまいちどうやって実装していくか想像がつかなかったので、WAI-ARIA Authoring Practicesで実装例を見ながら理解を深めていきました。
ボタンやチェックボックスなどで、どんな挙動が良いのかを実際にVoiceOverを使って触ってみれたのが結構勉強になったと思っています。

今でも悩みの種ではありますが、スクリーンリーダーを使ってこなかった身として、どんな挙動が理想なのかが本当にわからなかったので、自分の実装の指針になりました。

MDNではロールごとに関連するステートやプロパティが記載されている上、実装例もあるので、こちらも同じく理想像を作る上で助かりました。

あとは、開発後半にはなってしまいましたが、[WCAG](https://www.w3.org/TR/WCAG22/)でガイドラインもきちんと確認していきました。



##  どんな感じでスクリーンリーダー対応を行なっていったか

基本的には、一通り機能が実装し終わってから、スクリーンリーダーへの情報が足りない場所に手を加えていくという形で進めていきました。

スクリーンリーダーへの情報が足りない場所というのは、
- 閉じるボタンのようなテキスト情報がないコンポーネント(例１)
- やむを得ずdivやbuttonなどを使ってカスタムしたコンポーネント（例２）
のような場所です。

例1)閉じるボタン
![スクリーンショット 2021-12-03 1.31.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540090/c8a1dd57-0300-4df3-57c2-5bda70956d9b.png)
例2)カスタムしたラジオボタン(buttonで実装)
![スクリーンショット 2021-12-03 1.27.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/540090/16c7f3bc-5e7e-b19d-1bad-147fa946272d.png)


おおよその作業手順は以下のような感じです。
- スクリーンリーダーへの情報が足りない場所を見つける
- 実装例を見つけてくる
- 実装例を参考に実装してみる
- 実機で確認する

実装例に関しては、先程のAuthoring PracticesやMDNなどを参考にしました。
例えば、例２のラジオボタンに関してはMDNの[listboxロール](https://developer.mozilla.org/ja/docs/Web/Accessibility/ARIA/Roles/listbox_role)のページを参考にしています。

あとは必ず実機で確認するようにはしました。
後述しますが、割と想定通りの動きをしないことが多かったため、ユーザーが実際に利用する端末やブラウザで検証するようにしていました。

また、eslintのプラグインで[eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y)というものがあり、それを利用していました。
適切なWAI-ARIAのロールやステートの利用ができていない時にエラーを出してくれるので、とても便利でした。

## スクリーンリーダー対応で得た知見

### 最終的に実機での読み上げ確認が必要
当たり前と言えば当たり前ですが、実装がうまく動くかどうかは確認しないと分からないです。

[MDN](https://developer.mozilla.org/ja/docs/Learn/Accessibility/WAI-ARIA_basics#where_is_wai-aria_supported)にも書かれていますが、ブラウザ、OS、スクリーンリーダーの組み合わせやWAI-ARIAのサポート状況で、最終的に読み上げられるテキストが変わってくる場合があります。

例えば、モバイルのSafariとiOSのVoiceOverでは、groupロールがサポートされていません。
参考: https://a11ysupport.io/tech/aria/group_role

そのため、groupロールとaria-labelledbyを利用して関連のある情報をまとめようとしても、、モバイルのSafariとiOSのVoiceOverでは想像通りに読み上げが行われません。

そんな感じで、実装時に想定したものが必ずしもユーザーの端末でも同じ挙動をする保証がないので、最低でも開発時には想定のユーザーが利用する端末を用意して確認した方がいいです。

## 最後に
色々と分からないことだらけで、今でもスクリーンリーダー対応に対して自信はないですが、勉強だけは続けていこうと思います。