途中省略するページャーをCSSで表現する

ページャーの数が多い場合に一部省略されるようなデザインがたまにありますが、CMSの都合上実装が難しいという場合があります。
そういった場合にCSSで見た目上省略できないか試してみてみました。

サンプルコード

今回の省略される条件としては以下の通りです。

  • 先頭と最後の数字は常に表示する。
  • カレントとその前後2件まで(先頭と最後は除く)の数字は表示する。
  • 上記以外の数字は非表示にする。
  • 先頭の直後または最後の直前が省略されている場合、省略記号(…)を表示する。

実際に実装をしてみます。
まずはHTMLです。

<div class="pager">
  <ol class="pager_list">
    <li class="pager_item">
      <a href="" class="pager_link">1</a>
    </li>
    <li class="pager_item">
      <a href="" class="pager_link">2</a>
    </li>
    <li class="pager_item">
      <a href="" class="pager_link">3</a>
    </li>
    <li class="pager_item">
      <a href="" class="pager_link">4</a>
    </li>
    <li class="pager_item is-current">
      <a href="" class="pager_link">5</a>
    </li>
    <li class="pager_item">
      <a href="" class="pager_link">6</a>
    </li>
    <li class="pager_item">
      <a href="" class="pager_link">7</a>
    </li>
    <li class="pager_item">
      <a href="" class="pager_link">8</a>
    </li>
    <li class="pager_item">
      <a href="" class="pager_link">9</a>
    </li>
    <li class="pager_item">
      <a href="" class="pager_link">10</a>
    </li>
  </ol>
</div>

カレントの数字には.is-currentを追加する想定にしています。
上記の例で言うと5がカレントがついているため、3〜7と1と10が表示され、それ以外が非表示になります。

次にCSSです。
装飾部分は省いて、表示の制御を行っている部分のみ抜粋しています。

.pager_item {
	display: none;
}
.pager_item:first-child, /* 先頭 */
.pager_item:last-child, /* 最後 */
.pager_item.is-current, /* カレント */
.pager_item:has(+ .pager_item + .pager_item.is-current), /* カレントの2つ前 */
.pager_item:has(+ .pager_item.is-current), /* カレントの1つ前 */
.pager_item.is-current + .pager_item, /* カレントの1つ後 */
.pager_item.is-current + .pager_item + .pager_item { /* カレントの2つ後 */
	display: flex;
}
/* カレントの2つ前で、先頭または2番目の要素でない場合 */
.pager_item:has(+ .pager_item + .pager_item.is-current):not(:first-child):not(:nth-child(2))::before {
	content: '...';
}
/* カレントの2つ後で、最後または最後から2番目の要素でない場合 */
.pager_item.is-current + .pager_item + .pager_item:not(:last-child):not(:nth-last-child(2))::after {
	content: '...';
}

CSSについてはコメントで書いている通りですが、まず.pager_itemは基本非表示とした上で、4〜12行目で条件にあう.pager_itemのみ表示するようにしています。
省略記号の表示については13〜20行目で、カレントの2つ前と2つ後の.pager_itemに疑似要素で設定しています。

これでいくつかのパターンで試してみましたが、意図した表示になっていそうでした。
途中省略のページャー実装のデモページ

上記をベースに表示範囲も調整できます。
例えば、カレントの前後2件から1件に変更してみます。

.pager_item {
	display: none;
}
.pager_item:first-child, /* 先頭 */
.pager_item:last-child, /* 最後 */
.pager_item.is-current, /* カレント */
.pager_item:has(+ .pager_item.is-current), /* カレントの1つ前 */
.pager_item.is-current + .pager_item { /* カレントの1つ後 */
	display: flex;
}
/* カレントの1つ前で、先頭または2番目の要素でない場合 */
.pager_item:has(+ .pager_item.is-current):not(:first-child):not(:nth-child(2))::before {
	content: '...';
}
/* カレントの1つ後で、最後または最後から2番目の要素でない場合 */
.pager_item.is-current + .pager_item:not(:last-child):not(:nth-last-child(2))::after {
	content: '...';
}

これでカレントの前後1件が表示対象にできました。
省略範囲変更のデモページ

派生として、.pager_itemではなくその中のリンク(.pager_link)に対して.is-currentが付与される例も試してみます。

<div class="pager">
  <ol class="pager_list">
    <li class="pager_item">
      <a href="" class="pager_link">1</a>
    </li>
    〜 略 〜
    <li class="pager_item">
      <a href="" class="pager_link is-current">5</a>
    </li>
    〜 略 〜
    <li class="pager_item">
      <a href="" class="pager_link">10</a>
    </li>
  </ol>
</div>

基本的な実装は同じで、.is-currentの参照方法を調整しています。

.pager_item {
	display: none;
}
.pager_item:first-child, /* 先頭 */
.pager_item:last-child, /* 最後 */
.pager_item:has(.pager_link.is-current), /* カレント */
.pager_item:has(+ .pager_item + .pager_item .pager_link.is-current), /* カレントの2つ前 */
.pager_item:has(+ .pager_item .pager_link.is-current), /* カレントの1つ前 */
.pager_item:has(.pager_link.is-current) + .pager_item, /* カレントの1つ後 */
.pager_item:has(.pager_link.is-current) + .pager_item + .pager_item { /* カレントの2つ後 */
	display: flex;
}
/* カレントの2つ前で、先頭または2番目の要素でない場合 */
.pager_item:has(+ .pager_item + .pager_item .pager_link.is-current):not(:first-child):not(:nth-child(2))::before {
	content: '...';
}
/* カレントの2つ後で、最後または最後から2番目の要素でない場合 */
.pager_item:has(.pager_link.is-current) + .pager_item + .pager_item:not(:last-child):not(:nth-last-child(2))::after {
	content: '...';
}

これで最初と同じ表示になりました。
.is-currentの位置変更のデモページ

このエントリーをはてなブックマークに追加

関連記事

コメントを残す

メールアドレスが公開されることはありません。
* が付いている欄は必須項目です

CAPTCHA


コメントが承認されるまで時間がかかります。

2025年2月
 1
2345678
9101112131415
16171819202122
232425262728