# 現在のページも行き先も伝えないページネーション

Source: https://easeweb.dev/learn/pagination
Topics: メニューとナビゲーション > ページネーションが現在のページと各リンクの先を伝える (WCAG 1.3.1, 2.4.4)
The fix: ページのリンクを名前付きのnavに入れ、現在のページをコードかテキストで示し、ページのリンクすべてに言葉の名前を付けます。数字のデザインを残して、現在のページにaria-current="page"を付け、各数字と矢印に隠したテキストで名前を付けるか、数字をやめて「Page 2 of 4」の両側にPrevious pageとNext pageのリンクを置きます。
Test with: screen reader, keyboard, speech input
References: https://www.w3.org/WAI/WCAG22/Understanding/info-and-relationships.html https://www.w3.org/WAI/WCAG22/Understanding/link-purpose-in-context.html https://www.w3.org/WAI/WCAG22/Techniques/html/H97 https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/Reference/Attributes/aria-current https://design-system.service.gov.uk/components/pagination/

よくある問題を再現した学習用のサンプルです。実在のクライアントの診断結果ではありません。コードは出発点となる実装例のため、実際の製品でも確認してください。ここでは支援技術でのテスト結果は報告していません。

## 場面

ショップのマグカップのカテゴリーページは、ページのリンクの列で終わります。戻る矢印、1から4の数字、進む矢印です。見慣れた、すっきりしたデザインです。2ページ目では2が濃い四角の中に入ります。目で見る人には、4ページ中の2ページ目であること、矢印が1ページ目と3ページ目へ行くことがすぐに分かります。

スクリーンリーダーの利用者がTabキーで同じ列を移動すると、「‹、リンク」「1、リンク」「2、リンク」「3、リンク」「4、リンク」「›、リンク」と聞こえます。2が表示中の結果ページであること、そもそも数字がページであることは伝わりません。矢印は、スクリーンリーダーや音声がその記号に持つ名前で読まれるか、スクリーンリーダーと句読点の読み上げ設定によっては読まれないため、「次のページ」を意味するリンクが行き先を何も伝えません。列はナビゲーションとして読み上げられず、スクリーンリーダーのランドマーク一覧にも出ないので、長い商品一覧の最後にあるページのリンクへ移動する手段がありません。

## 確認できる問題

ページのリンクは関係を示しています。一つの一覧の中を移動するためのリンクのまとまりで、その一つが表示中のページです。WCAG 1.3.1「情報及び関係性」は、見た目で示した情報をコードかテキストでも伝えることを求めています。この例では、まとまりはレイアウトにしかありません。列は `div` 要素で、支援技術に対しては何もまとめないからです。達成方法H97は、関連するリンクを `nav` に入れることで1.3.1を満たします。現在のページも見た目にしかありません。`current` クラスはブラウザーにとって意味がないためです。

リンクは2.4.4「リンクの目的（コンテキスト内）」も満たしません。リンクの目的は、リンクのテキストだけか、テキストとプログラムが解釈できるコンテキスト（同じ文、段落、リストの項目、表のセル、そのセルに関連付けた見出しセル）から分かる必要があります。「›」は行き先を何も伝えず、「2」はこの一覧のページであることを伝えません。目で見る人は、商品一覧の下という列の位置と、矢印のよくある意味からそれを読み取りますが、マークアップはどちらも伝えません。リンクを囲む `div` も、スクリーンリーダーが参照できるコンテキストになりません。

## 利用者への影響

ページ送りは、ショップのカテゴリー、検索結果、ブログのアーカイブ、掲示板など、ほぼどの一覧の下にもあります。たいていは一つの共通コンポーネントから作られるため、一か所直せばサイト中の一覧に届きます。特に重要なのは、どこまで見たか、あとどれだけ残っているかを知る必要がある長い一覧です。

## 自動チェックとAIの限界

自動チェックは、「2」や「›」も含めて、すべてのリンクに名前があるとして合格にします。空のリンクは不合格になりますが、記号は通ります。`current` や `active` といったクラス名には意味がないので、一つのリンクが現在地として装飾されていることは分かりません。数字が行き先を伝えているかも判断できません。EaseWebの診断では、クラスや名前からページ送りと分かる場所で、表示中のページへのリンクが隣のリンクと違う見た目なのに `aria-current` も現在のページだと伝えるテキストもないものを報告します。名前全体が記号だけで、周りの文、リストの項目、セルにも言葉がないリンクも報告します。ナビゲーションのランドマークの外にあるページのリンクは、そのリンクを添えて、人が確認する項目として渡します。「2」のような数字だけのリンクも、その人の判断に任せます。手で書いたページ送りも、コンポーネントライブラリから写したものも、AIツールが生成したものも、確かめ方は同じです。二つのページでページのリンクを聞き、今いる場所と行き先が伝わるかを確かめてください。

## 修正前：クラスで現在のページを示し、矢印は記号だけのページのリンク

```html
<h1>Mugs</h1>
…
<div class="pagination">
  <a href="/kitchen/mugs?page=1">‹</a>
  <a href="/kitchen/mugs?page=1">1</a>
  <a href="/kitchen/mugs?page=2" class="current">2</a>
  <a href="/kitchen/mugs?page=3">3</a>
  <a href="/kitchen/mugs?page=4">4</a>
  <a href="/kitchen/mugs?page=3">›</a>
</div>
```

```css
.pagination {
  display: flex;
  gap: 0.25rem;
}
.pagination a {
  min-width: 2.5rem;
  border: 1px solid #c9d0d6;
  border-radius: 0.375rem;
  text-align: center;
}
.pagination .current {
  border-color: #1d1d1f;
  background: #1d1d1f;
  color: #fff;
  font-weight: bold;
}
```

`current` クラスは2の見た目を変えるだけで、`div` も何もまとめません。スクリーンリーダーは「2、リンク」と隣のリンクと同じように読み、矢印は「‹、リンク」「›、リンク」と読みます。

## 修正後：名前付きのnav、aria-current、隠したテキストの名前

```html
<h1>Mugs</h1>
…
<nav class="pagination" aria-label="Pagination">
  <ul>
    <li>
      <a href="/kitchen/mugs?page=1">
        <span aria-hidden="true">‹</span>
        <span class="visually-hidden">Previous page</span>
      </a>
    </li>
    <li>
      <a href="/kitchen/mugs?page=1">
        <span class="visually-hidden">Page </span>1
      </a>
    </li>
    <li>
      <a href="/kitchen/mugs?page=2" aria-current="page">
        <span class="visually-hidden">Page </span>2
      </a>
    </li>
    <li>
      <a href="/kitchen/mugs?page=3">
        <span class="visually-hidden">Page </span>3
      </a>
    </li>
    <li>
      <a href="/kitchen/mugs?page=4">
        <span class="visually-hidden">Page </span>4
      </a>
    </li>
    <li>
      <a href="/kitchen/mugs?page=3">
        <span aria-hidden="true">›</span>
        <span class="visually-hidden">Next page</span>
      </a>
    </li>
  </ul>
</nav>
```

```css
.pagination ul {
  display: flex;
  gap: 0.25rem;
  list-style: none;
  padding: 0;
}
.pagination a {
  min-width: 2.5rem;
  border: 1px solid #c9d0d6;
  border-radius: 0.375rem;
  text-align: center;
}
.pagination [aria-current="page"] {
  border-color: #1d1d1f;
  background: #1d1d1f;
  color: #fff;
  font-weight: bold;
}
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}
```

デザインは変わりません。数字も矢印も描かれたとおりに見えます。列が固有の名前を持つ `nav` になったため、スクリーンリーダーは入るときに「Pagination、ナビゲーション」と読み、ランドマーク一覧にも並びます。2に付けた `aria-current="page"` により、スクリーンリーダーはそこで「現在のページ」と読みます。濃い四角もこの属性で選ぶため、見た目とコードが別のリンクを示すことはありません。隠したテキストが「Page 2」「Previous page」「Next page」というリンクの名前になります。矢印の文字は `aria-hidden` で隠すので、名前に重ねて記号が読まれることはありません。

## 修正後：ページ数の両側に「前へ」と「次へ」

```html
<h1>Mugs</h1>
…
<nav class="pagination" aria-label="Pagination">
  <a href="/kitchen/mugs?page=1">
    <span aria-hidden="true">‹</span>
    Previous page
  </a>
  <p>Page 2 of 4</p>
  <a href="/kitchen/mugs?page=3">
    Next page
    <span aria-hidden="true">›</span>
  </a>
</nav>
```

```css
.pagination {
  display: flex;
  align-items: center;
  gap: 1rem;
}
.pagination a {
  padding: 0.5rem 0.75rem;
  border: 1px solid #c9d0d6;
  border-radius: 0.375rem;
}
.pagination p {
  margin: 0;
  font-weight: bold;
}
```

普段の見た目が変わります。数字の代わりに、行き先を言葉で示す二つのリンクを置き、その間に現在のページを「Page 2 of 4」とテキストで書きます。誰もが読めるテキストなので、隠すものも、示す状態もありません。スクリーンリーダーは「Pagination、ナビゲーション」「Previous page、リンク」「Page 2 of 4」「Next page、リンク」と読み、音声操作の利用者は書かれたとおりに「Next pageをクリック」と言えます。代わりに失うのは、ページを飛ばす操作です。40ページ中の2ページ目から40ページ目へ直接は行けず、1ページずつ進むことになります。

## どの方法を選ぶか

どちらも1.3.1と2.4.4を満たします。検索結果やアーカイブのように一覧が長いときや、ページを行き来するときは、数字を残して `aria-current` と隠した名前を付けてください。デザインは描かれたとおりのまま、見た目は属性から決まります。一覧が短いとき、スマートフォンでは数字がどのみち収まらないとき、すべての名前を目に見える形にしたいときは、ページ数の両側にPrevious pageとNext pageを置いてください。隠すものがなく、音声操作の利用者は見えたとおりに言えます。

## 実装の判断

ページのリンクには、ほかにも判断が必要な点があります。

- 隠したテキストの代わりの `aria-label`：`<a href="…" aria-label="Page 2">2</a>` でも同じ名前になります。ブラウザーの翻訳機能は、ページ内のテキストに比べて `aria-label` の翻訳が確実ではありません。
- 名前：スクリーンリーダーが「ナビゲーション」を補うので、「Pagination」で足ります。[区別できない複数のナビゲーションランドマーク](/ja/learn/landmark-names)を参照してください。同じページのリンクを一覧の上と下に置くときは、二つの `nav` に別の名前を付けるか、上の列を `nav` に入れないでください。
- 最初と最後のページ：1ページ目では、Previous pageを出さないか、ただのテキストにします。同じページへ行くリンクや、どこへも行かないリンクにはしません。ページ番号の間の省略記号は、リンクの外で、独立したリストの項目のテキストとして置きます。
- ページを読み込まずに変わる一覧：並べ替え、絞り込み、ページのリンクで結果をその場で入れ替えるときは、`aria-current` も一緒に移し、一覧が変わったことを伝えます。[読み上げられないSPAの画面遷移](/ja/learn/route-changes)を参照してください。
- ページタイトル：ページのタイトルを「Mugs、2/4ページ」のようにすると、スクリーンリーダー利用者はページを開いた時点でどこにいるか分かります。これは2.4.2「ページタイトル」の範囲で、[すべてのページで同じページタイトル](/ja/learn/page-title)で扱っています。

Windowsのコントラスト テーマでも現在のページが見分けられるようにします。強制配色では2の後ろの濃い塗りが消え、ほかの数字と同じに見えます。太字は残り、ほかより太い境界線を引けば、それも残ります。

## 修正の確認

1. コードかブラウザーの検証ツールで、ページのリンクが固有の名前の `nav` に入っていること、現在のページに `aria-current="page"`、隠したテキスト、テキストのページ数のいずれかがあること、ページのリンクの名前がすべて言葉であること、現在のページの見た目が同じ条件から設定されていることを確認する。
2. スクリーンリーダーのランドマーク一覧を開き、ページのリンクがサイトのメインメニューとは別の名前で並ぶか確認する。
3. ページのリンクを読み、各数字がページとして、現在のものが現在のページか「Page 2 of 4」として、各矢印がPrevious pageかNext pageとして読まれるか確認する。
4. 数字、「次へ」、ブラウザーの戻るボタンで別の結果ページへ移り、見た目と読み上げの両方が新しいページへ移ったか確認する。
5. 音声操作で「Next pageをクリック」と言い、次のページへのリンクが開くか確認する。

OS、ブラウザーと支援技術のバージョン、ビルド、実施日、各手順の実際の結果を記録してください。共通のページ送りのコンポーネントを変更した際は、再度確認します。

## 制限

このサンプルは、どの一覧でも同じ結果になることを保証するものではありません。`aria-current` やランドマークの読み上げ方はスクリーンリーダーによって異なり、記号の読み方は句読点の読み上げ設定で変わります。利用者が使うスクリーンリーダーで確かめてください。スクロールや「もっと見る」ボタンで続きを読み込む一覧には示すページがないため、別の配慮が必要です。同じページの上にあるパンくずリストには、別の問題があります。[現在のページを見た目だけで示すパンくずリスト](/ja/learn/breadcrumbs)を参照してください。サイトのメインメニューも、同じ属性で現在のページを示します。[現在のページを見た目だけで示すナビゲーション](/ja/learn/current-page)を参照してください。

---

このガイドをコーディングエージェントで使う: MCP https://easeweb.dev/mcp（設定は https://easeweb.dev/ja/services/developers）
