Swiperアクセシビリティ改善のススメ

**『un-T factory! XA Advent Calendar 2022』 15日目**です。
どうぞよろしくお願いします。

## はじめに
カルーセルを実装する際、アクセシビリティの設定はしていますか？
Swiperでは、デフォルトでaria属性・role属性がスライドやprev・nextボタン、ページネーションに付与されます。
ですが、それらは全て英語で設定されています。
日本人向けのサイトを制作するのであれば日本語で設定してあげるほうが親切ですよね。
意外と簡単に実装できますので、まだやったことがないという方はぜひ取り組んでみてください。

Swiperはv8.4.5を使用します。

## アクセシビリティに関するオプション
Swiperにはアクセシビリティに関する[オプション](https://swiperjs.com/swiper-api#accessibility-a11y)が用意されています。
### a11y
| オプション名 | 初期値 | 説明 |
|:---------- |:-----------: |:------------ |
|containerMessage|null|`.swiper`のスクリーンリーダー用メッセージ|
|containerRoleDescriptionMessage|null|`.swiper`の役割を説明するスクリーンリーダー用メッセージ。aria-roledescription属性の値|
|enabled|true|a11yオプションを有効にするかどうか|
|firstSlideMessage|'This is the first slide'|最初のスライドのスクリーンリーダー用メッセージ|
|id|null|`.swiper-wrapper`に設定するid属性の値。nullの場合は自動的に生成される|
|itemRoleDescriptionMessage|null|スライドの役割を説明するスクリーンリーダー用メッセージ。`.swiper-slide`のaria-roledescription属性の値|
|lastSlideMessage|'This is the last slide'|最後のスライドのスクリーンリーダー用メッセージ|
|nextSlideMessage|'Next slide'|「次へ」ボタンのスクリーンリーダー用メッセージ|
|notificationClass|'swiper-notification'|a11yを使用したら追加されるクラス名|
|paginationBulletMessage|'Go to slide {{index}}'|ページネーションのスクリーンリーダー用メッセージ|
|prevSlideMessage|'Previous slide'|「前へ」ボタンのスクリーンリーダー用メッセージ|
|slideLabelMessage|'{{index}} / {{slidesLength}}'|スライドのラベルを説明するスクリーンリーダー用メッセージ|
|slideRole|'group'|`.swiper-slide`のrole属性の値|

## スライドが画像のみの場合

日本語に変更したい部分を[a11yのオプション](https://swiperjs.com/swiper-api#accessibility-a11y)でお好みの内容に変更します。
※aria属性について知りたい方は@k__watanabeさんの「[今日から始める負担にならないWAI-ARIA](https://qiita.com/k__watanabe/items/70502233e25b3fa9e8c8)」がおすすめです。

また、[キーボード操作のオプション](https://swiperjs.com/swiper-api#keyboard-control)を設定すると、キーボードの ← → キーでスライドを操作できるようになります。
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="oNydoPy" data-user="iwahashi_a" style="height: 300px; 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/iwahashi_a/pen/oNydoPy">
  Untitled</a> by Iwahashi Aki (<a href="https://codepen.io/iwahashi_a">@iwahashi_a</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## スライド内にリンクが含まれている場合
ちょっと厄介なのがスライド内にテキストリンクやボタンを含んでいる場合です。
何も調整をしないままだとタブキー操作でのフォーカスが、現在表示されていないスライドにも当たってしまい操作性が悪くなります。

### :frowning2: 調整前
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="YzvJKmX" data-user="iwahashi_a" style="height: 300px; 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/iwahashi_a/pen/YzvJKmX">
  Untitled</a> by Iwahashi Aki (<a href="https://codepen.io/iwahashi_a">@iwahashi_a</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

### :slight_smile: 調整後
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="dyKNNWq" data-user="iwahashi_a" style="height: 300px; 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/iwahashi_a/pen/dyKNNWq">
  Swiper_</a> by Iwahashi Aki (<a href="https://codepen.io/iwahashi_a">@iwahashi_a</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

まずは表示中のスライドにのみフォーカスが当たるようにします。

```scss:SCSS
.swiper-slide {
  visibility: hidden;
  &.swiper-slide-active {
    visibility: visible;
  }
}
```

次に、Swiperに用意されている`slideChangeTransitionEnd`というイベントを使い、スライドが切り替わったタイミングでリンクにフォーカスが当たるようにします。
`slideChangeTransitionEnd`はスライド切り替えのアニメーション終了後のタイミングで発火します。
```js:JS
swiper.on('slideChangeTransitionEnd', () => {
  const link = document.querySelector(
    '.swiper-slide.swiper-slide-active .content a'
  );
  link.focus();
});
```

## アクセシビリティの設定は直接HTMLに設定できる？
可能です。
その場合はオプションの`enabled`を`false`にしてください。
ただしaria-labelやrole属性など、デフォルトのアクセシビリティ設定が全て消えるので、上級者向けに感じます。
```js:JS
a11y: {
  enabled: false,
}
```
<p class="codepen" data-height="300" data-default-tab="html,result" data-slug-hash="bGKyJZB" data-user="iwahashi_a" style="height: 300px; 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/iwahashi_a/pen/bGKyJZB">
  Untitled</a> by Iwahashi Aki (<a href="https://codepen.io/iwahashi_a">@iwahashi_a</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## おわりに
オプションを使えば結構お手軽に設定できますよね。
最近デジタル庁が公開した「[ウェブアクセシビリティ導入ガイドブック](https://www.digital.go.jp/resources/introduction-to-web-accessibility-guidebook/)」によると、ウェブアクセシビリティを確保することで、日本では428万人以上の人が恩恵を受けるそうです。
少しでも多くの人に快適にウェブを使ってもらうためにも、普段から心がけたいものです。