ウェブアクセシビリティ改善に取り組んだ話

こんにちは、グロービスで[「GLOBIS 学び放題」](https://unlimited.globis.co.jp/)のフロントエンドエンジニアをしているAgataです。

「GLOBIS 学び放題」では、[アクセシビリティ](https://www.gov-online.go.jp/useful/article/202310/2.html)改善に向けたプロジェクトを開始しました。この記事では活動を通じて学んだアクセシビリティの課題発見方法と解決方法を紹介します。


# ウェブアクセシビリティとは？

デジタル庁の[『ウェブアクセシビリティ導入ガイドブック』](https://www.digital.go.jp/assets/contents/node/basic_page/field_ref_resources/08ed88e1-d622-43cb-900b-84957ab87826/53f76eaa/20240329_introduction_to_weba11y.pdf)では、ウェブアクセシビリティは以下のように定義されています。

> ウェブアクセシビリティは、利用者の障害の有無やその程度、年齢や利用環境にかかわらず、ウェブで提供 されている情報やサービスを利用できること、またはその到達度を意味しています。


障害のある人や高齢者も含めて、様々なニーズがあるユーザーでもサービスを使える状態にするための努力です。

アクセシビリティの配慮例:
* キーボードのみで操作を可能にすること
    例：手の怪我、手の震えでマウスうまく操作できないユーザー
* 支援技術対応すること（スクリーンリーダなどで、サイトのコンテンツを読み上げる技術）
    例：目の病気・目の不自由さ


また、「電車内など音を出せない状況で動画・音声を確認したい」「怪我をしてしまい、マウスを使えない」「メガネを忘れてしまい文字が見づらい」など、誰でもアクセシビリティを必要になる可能性があります。



# アクセシビリティ課題を発見する3つの方法

アクセシビリティを最初から意識せずに開発を進めると、多くの課題を抱えることになります。
アクセシビリティをどれだけ確保できているのか現在の状況を確認するには、下記のような方法があります。

### 方法1：ツールによる分析

Lighthouseなどを使って、Accessibilityレポートをみることで、代替テキストやHTMLの不正解な書き方などを見つけることができます。

### 方法２：tabキーで操作してみる

ボタン、リンクなどの[focusable要素](https://web.dev/learn/accessibility/focus?hl=ja)はマウスを使わなくても、キーボードのtabキーをフォーカスを当てることが可能です。tabでナビゲーションすると、選ばれている要素に青い枠や線などが表示され、エンターを押すとボタンやリンクなどのアクションを発火できます。

![フォーカスされているボタンが青い枠で囲まれている。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640049/baf70894-8060-066e-b107-bcda5a558c2c.png)

フォーカス（青い枠・線）が表示されなかったり、何かの問題でtabを押しても次の要素に移動できないと、キーボード操作で利用したいユーザーはサイトでナビゲーションできなくなります。つまり、使えなくなります。

tabキーのみでサイトを操作できるか確認するのが、手動の確認方法になります。


### 方法３：スクリーンリーダー（音声読み上げ）を使ってみる

OSに搭載されている支援技術を利用し、確認することもできます。例えば、Macだと VoiceOver、 WindowsだとNVDAというスクリーンリーダーを使えます。スクリーンリーダーとは、音声読み上げ機能のことで、目が不自由なユーザーや音声でサイトを利用したいユーザーのために、サイトの内容を読み上げ、サイト内の操作を支援してくれるツールです。

操作に慣れるまで時間かかりますが、コンテンツが理解可能かどうか確認できます。

※ 他に確認することはいっぱいありますが、今回の記事のため上記に絞っておこうと思います。最終的には、[WCAGベースチェックリスト](https://waic.jp/translations/WCAG20/Overview.html)などにそって確認が必要になります

# アクセシビリティ課題を改善してみた！<br/> 開発しているサイトで見つけた２つ問題

上記の３つ方法で私たちのサイトを検証したところ、以下のような課題を発見し、改善していきました。

## 問題１：Tabキー操作で要素外に出られない無限ループが発生

### 現象

ヘッダーには、ロゴ（ホームへリンク）と検索の要素が配置されています。ヘッダーの下には、動画のプレイヤーとサイドメニューがあります。

![サイトの構成：ヘッダーには、ロゴ（ホームへリンク）と検索の要素が配置されています。ヘッダーの下には、動画のプレイヤーとサイドメニューがあります。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640049/bde783ea-90ec-47dd-af35-371523010141.png)

tabキーで検索を操作したところ、検索内の要素にフォーカスが当たり続けてしまい、無限ループが発生していました。Escキーを押しても反応せず、マウスを使わずに検索外に抜け出す方法がありませんでした。

![Tabキー操作で要素外に出られない無限ループの紹介動画。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640049/b5eb0309-89cc-3d64-b0c7-2c8ab7c44a40.gif)

### 改善

コードベースを確認したところ、原因を見つけることができました。

リンクのリストの中でトラップが実装されており、tabか矢印を押すと次の要素に行くように実装されていました。
参考にYouTubeの動きを確認してみました。そこにも同じようにリンクのリストがありましたが、動作は違いました。tabで検索から出ることができ、次のfocusable要素に行くことが可能でした。矢印でリストの中のナビゲーションは可能でした。もちろん、Escキーを押したら、検索要素を閉じることも可能でした。

![YouTubeの検索要素の例。tabとEscキーで検索の要素を出れます。矢印で検索の候補リストの中ナビゲーションできます。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640049/61ec6160-c57e-8059-1859-19430dbccf46.gif)

（動画はわかりにくいかもしれませんので、[YouTube](https://youtube.com/)でtab, shift tab, 矢印キーで遊んでみてください🙇）

実装方法を見直し、動画の再生ボタンまで辿り着けるようになりました！
しかし、スマートフォンで操作したところ、次の課題を発見しました。

## 問題２：強大なトグルボタン

スマートフォンに切り替えて、方法３のVoiceOverをonにしました。メニューを閉じるアイコンボタンをタップしても、シェアボタンをタップしても、「ボタン」としか読み上げられませんでした。音声でサイトを操作したいユーザーには、これらが何のボタンなのかを知ることができませんでした。そこで、各ボタンに「シェアボタン」など代替テキストを追加する修正をしました。

![ボタン改善例：元々「ボタン」としか読み上げてないボタンに代替テキストを追加することで、ボタンの意味が伝わるようになりました。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640049/d5aed705-4661-b9f0-a244-60438f7525fe.png)

次は、動画の再生ボタンを改善しました。
こちらも「トグルボタン」としか読み上げられず、動画の再生もできない状態でした。
DevToolsで調査したところ、サイドメニューの横に大きな透明なボタンが設置されているが判明しました。


![動画のプレイヤーを隠れている大きなボタン。どこに押しても、「ボタン」としか読み上げてなくて、動画の再生できない状態。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640049/7a8061c6-9020-6735-974b-13ac9e5c722d.png)

```react
<div 
  className=“transparent” 
  onClick={closeSideMenu}
  role=”button”   
  aria-label=”Toggle”   
  tabIndex={0} >    
    <Player/> 
</div>
```

これはサイドメニュー以外のところをタップすると、サイドメニューが自動的に閉じるための実装でした。そのため、動画プレイヤー周辺のレイアウトは元々透明なdivでラップされていて、divにonClickイベントが追加されていました。

![動画プレイヤーを隠している大きなボタンの存在理由。元々ボタンのおかげでサイドメニューをタップで隠すことが可能でした。](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3640049/8a2be7a5-9f0c-133b-eff5-216377d6218f.png)

ここはいくつか問題がありました：
* ```aria-label=”Toggle”```だと、何をトグルするか伝わらない
* divを使ってボタンが実装されている（できれば、[divでボタンを実装しないほうがいい](https://tech.anotherworks.co.jp/article/interactive-content-html-div-onclick) ）
* このdiv？ボタン？は中にあるコンテンツをかぶってしまい、スマートフォンでは一番上のレイヤーになってしまう。したがって、中にあるプレイヤーのコントロールボタンをタップできない

ロジックを書き直しました。上記のdivの```onClick```, ```role```, ```aria-label```, ```tabIndex```を削除して、ロジックをサイドメニューコンポーネントで改めて実装し直しました（[handle click outside divのイベントハンドラー](https://stackoverflow.com/questions/36695438/detect-click-outside-div-using-javascript) を追加することで、特にボタンをどこかで追加しなくても済むことができました）。
再生ボタンをクリックできるようになりました! 🥳

# 最後に

アクセシビリティ観点では上のような問題が放置されたままではマウス操作が必要となり、改善の余地がありました。このほかにも問題を発見し、ところどころHTMLの書き直しなどを行っていきました。
修正の結果、視聴ページのLighthouseスコアが１０％アップされ、より幅広くコンテンツを提供することが可能になりました。


今回のアクセシビリティ改善活動を通じて、divをボタンにしたり、キーボードの操作を上書きするのは避けたほうが良いことを学びました。HTMLは幅広いユーザーにコンテンツを提供する前提で作られていたマークアップで、この良さを使わないのはもったいないことです。

これからも[グロービス学び放題](https://unlimited.globis.co.jp/)のアクセシビリティ改善を楽しみにしてください〜😊