【アクセシビリティ】アクセシビリティを意識したフィードの作り方

## はじめに
![](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/390720/62845074-9546-5c7a-4c52-f39e71d3f80b.png)

みなさんアクセシビリティを意識して開発できていますか？

必要なところに`role属性`を記述したり、`tabキー`でフォーカスができるようにしたりなど、意識しないといけないことも多いです。
そのため、アクセシビリティを完璧にやろうとするのは一苦労です。

ただ、コンポーネントごとに区切って、アクセシビリティを理解しておけば、実装するタイミングに思い出しやすく、アクセシビリティも意識しやすいと思います。

そのため、この記事では「**フィード**」に焦点を当てて、アクセシビリティを意識したフィードの実装方法とフィードで意識した方がいいアクセシビリティを解説しようと思います。

## アクセシビリティを意識したフィードの仕様
### ⚪︎ フィードとは？
フィードは、ユーザーがスクロールするとコンテンツの新しいセクションを自動的にロードする要素です。
フィード内のコンテンツは、`<article>` で表示します。

また多くのフィードは、無限スクロールのように見える記事の動的なリストであると考えられます。

フィード要素は、webページと支援技術の間で、以下のような取り決めがあります。

+ **webページ**
  + フォーカスがあるArticle要素をユーザーが見える範囲に適切にスクロールすること
  + フォーカスがあるArticle要素に基づいて、新しいArticle要素を読み込んだり、既存のArticle要素を削除すること
+ **支援技術**
  + Article要素 or Article要素の子孫要素にフォーカスがあるかを読み上げること
  + 前後の記事にフォーカスが移動するための読み上げモードのキーを提供すること
  + 読み上げモードのキーを提供することで、読み上げカーソルとDOMフォーカスを移動させること

### ⚪︎ キーボードインタラクション

+ **`Page downキー`**
  + 次の記事にフォーカスを移動する
+ **`Page upキー`**
  + 前の記事にフォーカスを移動する
+ **`Controlキー + Endキー`**
  + フィード要素の次のフォーカス可能な要素にフォーカスを移動する
+ **`Controlキー + Homeキー`**
  + フィード要素の前のフォーカス可能な要素にフォーカスを移動する

:::note warn
+ 例が少ないので、キーボード操作のドキュメントがわかるようにする必要がある
+ フィードの中にフィードがある場合
  + `Altキー + Page downキー` で入れ子のフィード内の最初のアイテムにフォーカスを移動する
  + `Controlキー + Endキー` で他のフィードの次の記事にフォーカスを移動する
+ 文字上記のキーがフィード内の要素で必要の場合は、他のキーでフォーカスを移動する必要がある
:::

### ⚪︎ WAI-ARIA の役割、状態、プロパティ
+ フィードには、`role="feed"` を設定する
+ フィードに表示させるラベルがある場合、フィード要素にはタイトルを含む要素を指す `aria-labelledby` を設定する
  + それ以外の場合、フィード要素には、`aria-label` で指定されたラベルが設定される
+ フィード内のすべてのコンテンツは、`role="article"` を設定する
+ 各Article要素には、その中の要素を区別するラベルとして機能できる要素を指す `aria-labelledby` を設定する
  + この `aria-describedby` を持つことは任意ですが、強く推奨する
+ 各Article要素には、フィード内での位置を表す値として、`aria-posinset` を設定する
+ 各Article要素には、読み込まれた記事の総数またはフィード内の総数を表す `aria-setsize` を設定する
  + フィード内の総数が不明な場合、`aria-setsize="-1"` が使用されることがある
+ Article要素がフィードコンテナに追加または削除され、その操作に複数のDOM操作が必要な場合、更新操作中にfeed要素の `aria-busy="true"` を設定する
  + 操作が完了した場合、`aria-busy="false"` に設定しないと、変更が一部の支援技術ユーザーには表示されない可能性がある

## アクセシビリティを意識したフィードの完成形
<p class="codepen" data-height="400" data-default-tab="result" data-slug-hash="eYxJVPo" data-editable="true" data-user="sp_degu" style="height: 400px; 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/sp_degu/pen/eYxJVPo">
  Checkbox Accessibility</a> by でぐぅー | Qiita (<a href="https://codepen.io/sp_degu">@sp_degu</a>)
  on <a href="https://codepen.io">CodePen</a>.</span>
</p>
<script async src="https://cpwebassets.codepen.io/assets/embed/ei.js"></script>

## アクセシビリティを意識したフィードの作り方
### 1. HTMLを実装する
```sample.html
<div role="feed" aria-label="記事一覧">
  <article class="article" aria-labelledby="article-title" aria-posinset="1" aria-setsize="6">
    <h2 id="article-title">【まとめ】2022年に話題になったWebサイト</h2>
    <div class="article-info">
      <p>degudegu2510</p>
      <time datetime="2023-01-11">2023/01/11</time>
    </div>
  </article>
  <article class="article" aria-labelledby="article-title" aria-posinset="2" aria-setsize="6">
    <h2 id="article-title">【CSS】borderを使って、三角形を作るのはやめませんか？</h2>
    <div class="article-info">
      <p>degudegu2510</p>
      <time datetime="2023-01-11">2023/06/18</time>
    </div>
  </article>
  <article class="article" aria-labelledby="article-title" aria-posinset="3" aria-setsize="6">
    <h2 id="article-title">【CSS】CSSの値と単位が新しくなっていますが、ついていけてますか？</h2>
    <div class="article-info">
      <p>degudegu2510</p>
      <time datetime="2023-01-11">2023/07/12</time>
    </div>
  </article>
  <article class="article" aria-labelledby="article-title" aria-posinset="4" aria-setsize="6">
    <h2 id="article-title">【まとめ】2022年に話題になったWebサイト</h2>
    <div class="article-info">
      <p>degudegu2510</p>
      <time datetime="2023-01-11">2023/01/11</time>
    </div>
  </article>
  <article class="article" aria-labelledby="article-title" aria-posinset="5" aria-setsize="6">
    <h2 id="article-title">【CSS】borderを使って、三角形を作るのはやめませんか？</h2>
    <div class="article-info">
      <p>degudegu2510</p>
      <time datetime="2023-01-11">2023/06/18</time>
    </div>
  </article>
  <article class="article" aria-labelledby="article-title" aria-posinset="6" aria-setsize="6">
    <h2 id="article-title">【CSS】CSSの値と単位が新しくなっていますが、ついていけてますか？</h2>
    <div class="article-info">
      <p>degudegu2510</p>
      <time datetime="2023-01-11">2023/07/12</time>
    </div>
  </article>
</div>
```

### ２. CSSを実装する
```sample.css
body {
  background-color: #212529;
  color: #fff;
  margin: 0;
  padding: 24px 0;
  width: 100vw;
}

div[role="feed"] {
  align-items: center;
  display: grid;
  gap: 16px;
  justify-content: center;
}

.article {
  background-color: rgb(128 128 128 / .3);
  border-radius: 24px;
  display: grid;
  gap: 8px;
  padding: 16px;
  position: relative;
  width: 300px;
  background-blend-mode: luminosity;
  backdrop-filter: blur(15px);
  &::before {
    background: linear-gradient(135deg, rgb(255 255 255 / .4) 0, rgb(255 255 255 / 0) 40%, rgb(255 255 255 / 0) 60%, rgb(255 255 255 / .1) 100%);
    border: 1.4px solid transparent;
    border-radius: 24px;
    content: "";
    inset: 0;
    position: absolute;
    -webkit-mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0) border-box;
    -webkit-mask-composite: destination-out;
    mask: linear-gradient(#fff 0 0) padding-box, linear-gradient(#fff 0 0) border-box;
    mask-composite: exclude;
    z-index: -1;
  }
}

h2 {
  font-size: 18px;
  margin: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.article-info {
  color: rgb(255 255 255 / .6);
  font-size: 14px;
  display: flex;
  justify-content: space-between;
}

p {
  margin: 0;
}
```

## まとめ
この記事では、「**フィード**」に焦点を当てて、アクセシビリティを意識したフィードの実装方法とフィードで意識した方がいいアクセシビリティを解説しました。

ぜひこの記事をストックして、フィードを実装する時にアクセシビリティについて思い出してもらえると嬉しいです。

Advent Calendar 2023では、他のコンポーネントにも焦点を当てて、アクセシビリティについても解説しているので、ぜひ購読していてください。

https://qiita.com/advent-calendar/2023/degudegu2510

---

最後まで読んでくださってありがとうございます！

普段はデザインやフロントエンドを中心にQiitaに記事を投稿しているので、ぜひQiitaのフォローとX(Twitter)のフォローをお願いします。

https://twitter.com/degudegu2510