ページネーション 実装解説|Pagination CSS Guide

ページネーション デザイン見本

記事一覧や検索結果を複数ページに分割する「ページネーション」の実装デモ。番号送り・省略表示(…)・デザインのバリエーションを収録し、コピーしてすぐに使える HTML・CSS・JS のコードを掲載。
HTML・CSS・JSコードプレビューツール にて実装確認ができます。

① 基本の番号送り(前へ / 番号 / 次へ)

1 ページ目を表示中

HTML
<nav class="pager" aria-label="ページネーション">
  <button data-nav="prev" aria-label="前のページ" disabled>‹</button>
  <button data-page="1" class="active">1</button>
  <button data-page="2">2</button>
  <button data-page="3">3</button>
  <button data-page="4">4</button>
  <button data-page="5">5</button>
  <button data-nav="next" aria-label="次のページ">›</button>
</nav>
CSS
.pager {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.pager button {
  min-width: 38px;
  height: 38px;
  padding: 0 10px;
  border: 1px solid #e2e8f0;
  background: #fff;
  color: #334155;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.pager button:hover:not(:disabled):not(.active) {
  background: #f1f5f9;
  border-color: #cbd5e1;
}
.pager button.active {
  background: #667eea;
  border-color: #667eea;
  color: #fff;
}
.pager button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
JS
(function () {
  var pager = document.querySelector('.pager');
  if (!pager) return;
  var nums = pager.querySelectorAll('[data-page]');
  var prev = pager.querySelector('[data-nav="prev"]');
  var next = pager.querySelector('[data-nav="next"]');
  var current = 1;
  var last = nums.length;

  function render() {
    nums.forEach(function (b) {
      b.className = Number(b.getAttribute('data-page')) === current ? 'active' : '';
    });
    prev.disabled = current === 1;
    next.disabled = current === last;
  }
  nums.forEach(function (b) {
    b.addEventListener('click', function () {
      current = Number(b.getAttribute('data-page'));
      render();
    });
  });
  prev.addEventListener('click', function () {
    if (current > 1) { current--; render(); }
  });
  next.addEventListener('click', function () {
    if (current < last) { current++; render(); }
  });
  render();
})();
current を1つ持って再描画する

現在ページを表す current という変数を1つだけ用意し、番号ボタンのクリックでその値を書き換えて render() を呼び直すのが基本形。render() では全ボタンの active クラスを付け直し、先頭ページなら「前へ」、末尾ページなら「次へ」を disabled にする。状態は current 1つに集約されるので、表示と実データがズレにくい。

② 省略表示(… で中間ページを省く)

HTML
<nav class="pager" aria-label="ページネーション"></nav>
CSS
.pager {
  display: inline-flex;
  flex-wrap: wrap;
  gap: 6px;
  align-items: center;
}
.pager button {
  min-width: 38px;
  height: 38px;
  padding: 0 10px;
  border: 1px solid #e2e8f0;
  background: #fff;
  color: #334155;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}
.pager button:hover:not(:disabled):not(.active) {
  background: #f1f5f9;
  border-color: #cbd5e1;
}
.pager button.active {
  background: #667eea;
  border-color: #667eea;
  color: #fff;
}
.pager button:disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
.pager .ellipsis {
  min-width: auto;
  padding: 0 4px;
  color: #94a3b8;
  font-weight: 700;
}
JS
(function () {
  var pager = document.querySelector('.pager');
  if (!pager) return;
  var totalPages = 12;
  var current = 1;

  function makeBtn(pageNum) {
    var b = document.createElement('button');
    b.textContent = pageNum;
    if (pageNum === current) b.className = 'active';
    b.addEventListener('click', function () { current = pageNum; render(); });
    return b;
  }
  function makeEllipsis() {
    var span = document.createElement('span');
    span.className = 'ellipsis';
    span.textContent = '…';
    return span;
  }
  function makeNav(dir, label, disabled) {
    var b = document.createElement('button');
    b.textContent = label;
    b.disabled = disabled;
    b.addEventListener('click', function () { current += dir; render(); });
    return b;
  }
  function render() {
    pager.textContent = '';
    pager.appendChild(makeNav(-1, '‹', current === 1));
    var pages = [1];
    for (var i = current - 1; i <= current + 1; i++) {
      if (i > 1 && i < totalPages) pages.push(i);
    }
    if (totalPages > 1) pages.push(totalPages);
    var prevNum = 0;
    pages.forEach(function (p) {
      if (p - prevNum > 1) pager.appendChild(makeEllipsis());
      pager.appendChild(makeBtn(p));
      prevNum = p;
    });
    pager.appendChild(makeNav(1, '›', current === totalPages));
  }
  render();
})();
先頭・末尾・現在ページ周辺だけを表示する

総ページ数が多いとき、全番号を並べると横に長くなりすぎる。そこで「1(先頭)」「現在ページの前後」「最終ページ」だけを表示し、間隔が空いた箇所に … を差し込む。表示するページ番号の配列を作り、前の番号との差が2以上なら省略記号を入れる、という手順にすると分岐が少なく読みやすい。ボタンは createElement と textContent で組み立て、innerHTML は使わない。

③ デザインのバリエーション(丸 / ピル / ミニマル)

HTML
<nav class="pager round">
  <button>1</button><button class="active">2</button><button>3</button>
</nav>

<nav class="pager pill">
  <button>1</button><button class="active">2</button><button>3</button>
</nav>

<nav class="pager minimal">
  <button>1</button><button class="active">2</button><button>3</button>
</nav>
CSS
.pager {
  display: inline-flex;
  gap: 6px;
  align-items: center;
}
.pager button {
  min-width: 38px;
  height: 38px;
  padding: 0 10px;
  border: 1px solid #e2e8f0;
  background: #fff;
  color: #334155;
  border-radius: 8px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
}
.pager button.active {
  background: #667eea;
  border-color: #667eea;
  color: #fff;
}

.pager.round button {
  border-radius: 50%;
  padding: 0;
}

.pager.pill button {
  border-radius: 999px;
}
.pager.pill button.active {
  background: linear-gradient(135deg, #f093fb, #f5576c);
  border-color: transparent;
}

.pager.minimal button {
  border: none;
  background: transparent;
  color: #64748b;
  border-radius: 0;
}
.pager.minimal button.active {
  color: #1a1a2e;
  border-bottom: 2px solid #667eea;
}
土台を共通化し、形は modifier で足す

ボタンの基本サイズや余白は .pager button にまとめておき、見た目の違いは .round・.pill・.minimal といった修飾クラスで上書きする。円形は border-radius: 50%、ピルは 999px、ミニマルは枠線を消して下線だけにする、という具合。土台が共通なので、サイト全体でサイズ感を揃えたままテーマだけ切り替えられる。

実装のヒント:実際のサイトでは、ページ番号のクリックで location.href?page=2 のように変える方式(サーバー側でページ生成)と、JavaScript で表示内容だけ差し替える方式(SPA的)があります。上のデモは後者の考え方で、番号の状態管理だけを示しています。SEOを重視する一覧では、各ページが実URLを持つ前者が無難です。

当サイトで公開しているWebデザインやUIの実装例は、一覧として以下記事に纏めています。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次