第22回 記事一覧の上部にもページナビを追加―10件表示を上下から移動できるようにする

記事一覧、カテゴリ、サブカテゴリ、連載詳細で、一覧末尾だけにあったページナビを上部にも追加しました。上下のナビを共通コンポーネント化し、同じpage・sort状態を使うようにした内容を記録します。

執筆:ゆまラボ運営者

公開:更新:
第22回 記事一覧の上部にもページナビを追加―10件表示を上下から移動できるようにする

第21回では、記事一覧・カテゴリ・サブカテゴリ・連載詳細を1ページ10件に変更し、「新しい順 / 古い順」とページ移動を追加した。

ページを分けたことで、30件を超えた記事を1ページに全部並べる状態は解消した。一方で実際の画面を使っていると、もう1か所気になるところが出てきた。

ページ移動の「最初 / 前へ / 1 / 4 / 次へ / 最後」が一覧の末尾にしかない。

1ページ10件なら大きな問題にはならないが、2ページ目へ進みたいだけでも毎回10記事分を下までスクロールする必要がある。記事がさらに増えても同じ動きになるので、今回はページナビを一覧上部にも追加する。

修正前は並び順だけが上部にあった#

修正前の記事一覧では、上部にある操作は「並び順」だけだった。

修正前の記事一覧上部。並び順だけが表示されている

ページ移動は記事を10件読み進めたあと、一覧末尾まで来たところで表示される。

修正前の記事一覧下部にあるページナビ

第21回で追加したページネーションそのものは正常に動いているので、今回はページ数の計算や?page=の仕組みを作り直す必要はない。

変更したいのは配置だけになる。

並び順
ページナビ

記事 10件

ページナビ

上部と下部のどちらからでも同じページへ移動できる形にする。

ページナビをPaginationNavへ切り出す#

修正前はPaginatedArticleList.astroの中にページナビのHTMLが直接あり、下部に1回だけ出力していた。

このまま同じHTMLを上にもコピーすれば見た目だけは実現できる。ただ、ページリンクの生成やdisabled状態を2か所で持つと、あとで片方だけ修正して表示がずれる可能性がある。

そこでページナビ部分を新しいPaginationNav.astroへ切り出した。

PaginatedArticleList.astroからは、同じ現在ページと総ページ数を渡して上下2回呼び出す。

PaginatedArticleList
├─ PaginationNav position="top"
├─ 記事一覧
└─ PaginationNav position="bottom"

上部と下部は別々のページ状態を持たない。

共有しているのは次の値と処理になる。

  • current page
  • sort
  • ?page=
  • ?sort=
  • 最初 / 前へ / 次へ / 最後のdisabled状態
  • ブラウザの戻る / 進む
  • 上下に表示する現在ページ番号

上部のdata-pageリンクを操作しても、下部を操作しても、最終的に同じ状態へ更新される。

上部ページナビを並び順の下へ追加#

修正後の/blog/では、並び順の下にページナビが表示されるようになった。

記事一覧上部へ1 / 4のページナビを追加した状態

作業時点の記事数は33件なので、1ページ10件で4ページになる。

1ページ目では、先頭側の「最初」と「前へ」は無効。次へ進める「次へ」「最後」はリンクとして使える。

ページナビをソートの横へ無理に詰め込まず、その下へ置いた。横幅が狭くなっても並び順とページ移動が干渉しにくい。

2ページ目でも上下の状態をそろえる#

上部ナビから2ページ目へ移動すると、上部の表示は2 / 4へ変わる。

記事一覧2ページ目の上部ページナビ

同じページの末尾まで移動すると、下部も2 / 4になっている。

記事一覧2ページ目の下部ページナビ

上下を別々に実装したのではなく、同じPaginatedArticleListの状態から両方を更新しているので、片方だけ1ページ目のまま残ることはない。

?page=?sort=の扱いも第21回のまま維持している。

?page=2
?sort=oldest
?sort=oldest&page=2

ソートを変更した場合は1ページ目へ戻る。不正なページ番号は有効範囲へ補正する。ブラウザの戻る・進むでも表示を復元する。

今回の変更で、URLの形式は増やしていない。

カテゴリとサブカテゴリにも同じナビを使う#

上部ページナビは/blog/だけに追加したわけではない。

PaginatedArticleListを使用しているカテゴリとサブカテゴリにも同じ変更が入る。

たとえば「WEB制作 > 運用・改善」は作業時点で13記事あるため、10件と3件の2ページになる。

運用・改善ページの上部に1 / 2のページナビを表示した状態

カテゴリ説明、記事件数、並び順はそのまま残し、その下に上部ページナビを追加している。

ページが1つしかない分類では、上下ともページナビを表示しない。記事が少ないページに「1 / 1」だけの操作を増やさないようにした。

作業時点の主なページ数は以下。

横にスクロールできます
対象記事件数ページ数
記事一覧33件4ページ
WEB制作26件3ページ
運用・改善13件2ページ
Astro+Cloudflareでサイトを作る22件3ページ

記事公開後は件数が増えるため、この数値は実装時点のものになる。ページ数自体は記事数から自動計算される。

連載ページでも第1回から読む順序を維持する#

連載詳細にも同じ上部ページナビを追加した。

連載詳細に上部ページナビを追加し、第1回から表示している状態

ここは通常の記事一覧とソート基準が違う。

前回修正したとおり、/blog/、カテゴリ、サブカテゴリはpubDate、連載詳細はseriesOrderを使う。

/blog/
カテゴリ
サブカテゴリ
  新しい順 → pubDate 降順
  古い順   → pubDate 昇順

連載詳細
  古い順   → seriesOrder 昇順
  新しい順 → seriesOrder 降順

今回ページナビを共通化しても、このルールは変更していない。

「Astro+Cloudflareでサイトを作る」で古い順を選ぶと、1ページ目はseriesOrder 1~10、2ページ目は11~20、3ページ目は21~22になる。新しい順では逆方向から表示する。

番外編を含む内部順序もこれまでどおりseriesOrderで管理する。

上下のnavには別のaria-labelを付ける#

同じページにページナビが2つ存在するため、HTML上では位置を区別できるようにした。

上部は、

aria-label="上部ページナビゲーション"

下部は、

aria-label="下部ページナビゲーション"

を使う。

現在ページには既存のaria-current="page"を維持している。

見た目は同じページナビでも、支援技術側からは上部と下部を区別できるようにした。

ビルドと表示を確認する#

今回変更した主なファイルは2つ。

src/components/PaginationNav.astro
src/components/PaginatedArticleList.astro

実装中、新しく作ったPaginationNav.astroでAstroのフロントマター区切りが不足し、一度ビルドエラーになった。区切りを修正したあと、再度ビルドと検証を行っている。

実行したコマンドは下記。

npm run build
node scripts/verify.mjs
git diff --check
astro preview --background --host 127.0.0.1

最終ビルドは成功し、117ページを生成した。

Pagefindは33ページ、3,023語を対象に生成。RSS、sitemap、タグページのnoindex、BreadcrumbList JSON-LDも既存の状態を維持している。

ブラウザでは上下ナビのページ状態、?page=?sort=、連載の古い順・新しい順を確認した。

レスポンシブ確認では、使用したヘッドレスブラウザの制約で320~390px指定時の実測viewportが500pxになった。そのため500pxでの実表示と、max-width: 520px / 720pxのCSS条件を確認している。320pxで実測したとは扱わない。

上下ページナビの変更点#

第21回で追加した10件表示の仕組みはそのまま残し、ページ移動の入口だけを上下へ増やした。

  • ページナビをPaginationNav.astroへ共通化
  • 一覧上部にも「最初 / 前へ / 現在ページ / 次へ / 最後」を追加
  • 下部ページナビはそのまま維持
  • 上下でcurrent page、sort、URL queryを共有
  • 1ページだけの一覧では上下とも非表示
  • /blog/、カテゴリ、サブカテゴリ、連載詳細へ反映
  • 連載のseriesOrder基準は変更しない

これで、2ページ目以降へ移動するために毎回10記事分を下までスクロールする必要はなくなった。