【JavaScript】戻る・進むボタンを実装する方法

「前のページに戻る」「1つ進む」ボタンをページ内に置きたいとき、JavaScriptのhistory オブジェクトを使えば数行で実装できます。ブラウザのツールバーにある戻る/進むボタンと同じ動きを、自分のボタンで再現できます。

基本は history.back()history.forward() だけですが、実務では「戻り先が無いときどうするか」「SPAでの戻る対応」などつまずきやすい点があります。この記事ではそこまで含めてそのまま動くコードで解説します。

この記事の結論:戻るは history.back()、進むは history.forward()、複数ページの移動は history.go(n)(負で戻る/正で進む)で実装します。ただし「戻り先があるか」をJavaScriptで正確に判定する方法はありません。履歴が無いときはトップページへ飛ばすなどのフォールバックを用意します。
スポンサーリンク

戻る・進むボタンの基本実装

ボタンにイベントを割り当て、クリックで history.back() / history.forward() を呼ぶだけです。window.history は単に history と書いても同じものを指します。

HTML
<button id="back">戻る</button>
<button id="forward">進む</button>
JavaScript
// HTMLとロジックを分けるため addEventListener で割り当てる
document.getElementById("back").addEventListener("click", () => {
  history.back();    // 1つ前の履歴へ
});

document.getElementById("forward").addEventListener("click", () => {
  history.forward(); // 1つ先の履歴へ
});

古い記事では <button onclick="goBack()"> のようにHTML属性へ直接書く例も見かけますが、現在は上のように addEventListener でJavaScript側にまとめるのが一般的です。

history.go(n)で複数ページ移動する

history.go() に整数を渡すと、その分だけまとめて移動できます。back() / forward()go(-1) / go(1) と同じです。

JavaScript:go(n) の使い方
history.go(-1);  // 1つ戻る(back() と同じ)
history.go(1);   // 1つ進む(forward() と同じ)
history.go(-2);  // 2つ前のページへ一気に戻る
history.go(0);   // 現在のページを再読み込み(リロード)
注意:history.go(0) と引数なしの history.go()現在ページのリロードになります。移動のつもりで 0 を渡さないよう注意してください。

「戻れるか・進めるか」は判定できない

「戻り先が無いときはボタンを無効化したい」と考えがちですが、ブラウザには「戻れるか」を調べる標準APIがありませんcanGoBack のようなものは存在しません)。プライバシー保護のための仕様です。

history.length も当てになりません:history.length はそのタブの履歴件数を返しますが、他サイトを経由した分も含まれ、現在位置が何番目かは取得できません。 「進める履歴があるか」の判定には使えないと考えてください。

また、履歴の先頭(最初に開いたページ)で history.back() を呼んでも何も起きません。ボタンが効かないように見えるため、履歴が無いときはトップページなどへ飛ばすフォールバックが有効です。

JavaScript:履歴が無ければトップへ
document.getElementById("back").addEventListener("click", () => {
  if (history.length > 1) {
    history.back();          // 履歴があれば戻る
  } else {
    location.href = "/";     // 直接開かれた場合などはトップへ
  }
});

これも完全な判定ではありませんが(history.length の制約があるため)、「直接URLを開いて戻り先が無い」ケースの保険としては実用的です。

popstateで履歴の移動を検知する

戻る・進むで履歴が切り替わったタイミングを検知したいときは popstate イベントを使います。back() / forward() / go() やブラウザのボタン操作で発火します。

JavaScript:popstate で検知
window.addEventListener("popstate", (event) => {
  console.log("履歴が移動しました");
  console.log(event.state); // pushState で保存した状態(無ければ null)
});

なお pushState() / replaceState() を呼んだだけではpopstate は発火しません。あくまで履歴の移動(戻る・進む)のときだけ呼ばれます。

SPAでの「戻る」対応(History API)

ページ全体を再読み込みしないSPA(シングルページアプリ)では、history.pushState() でURLと状態を履歴に積み、popstate で戻る・進むに合わせて画面を復元します。

JavaScript:pushState で状態を積む
// 画面遷移のたびに状態とURLを履歴へ追加
history.pushState({ view: "detail", id: 12 }, "", "/items/12");

// 戻る・進むで呼ばれ、保存した状態から画面を復元
window.addEventListener("popstate", (event) => {
  const state = event.state;
  if (state) renderView(state); // 例: 状態に応じて再描画
});

Vue RouterやReact Routerなどのルーターは、この仕組みを内部で自動的に扱っています。なお「戻るボタンを押させたくない(無効化したい)」という逆の要望と、なぜ完全には無効化できないのかはブラウザの戻るボタンを無効化する方法で詳しく解説しています。

history による移動と location の違い

history.back() などは履歴の中を行き来する操作で、移動先のURLを指定することはできません。一方、特定のURLへ移動したい場合は location.href = "..." を使います。こちらは新しい履歴エントリを追加して指定したページへ遷移します。

  • 戻る・進む(履歴の前後へ)→ history.back() / forward() / go(n)
  • 特定URLへ移動URLを遷移させる方法location

現在のURLそのものを取得したいときは現在のURLを取得する方法も参考になります。

よくある質問(FAQ)

QJavaScriptでブラウザの戻る・進むを制御するには?
Ahistory.back() で戻る、history.forward() で進む、history.go(n) でn段階の移動ができます(負で戻る/正で進む)。履歴の移動は popstate イベントで検知して追加処理を行えます。
Q戻る先があるかどうかを判定できますか?
Aいいえ、正確には判定できませんcanGoBack のような標準APIは無く、history.length も他サイト経由分を含み現在位置が分からないため当てになりません。履歴が無いときは location.href = "/" でトップへ飛ばすなどのフォールバックで対応します。
QSPAで戻るボタンを適切に動作させるには?
Ahistory.pushState() でURLと状態を履歴に積み、popstate イベントでルーティング処理を行ってページ状態を復元します。Vue RouterやReact Routerはこれを自動で処理します。
Q特定の状態へ戻る処理を実装するには?
Ahistory.pushState({ data: state }, "", url) でカスタムデータを履歴に保存し、popstateevent.state から取り出して画面を復元します。

まとめ

ページ内の戻る・進むボタンは、history.back() / history.forward() / history.go(n) の3つで実装できます。go(0) はリロードになる点に注意してください。

ただし「戻り先があるか」をJavaScriptで正確に知ることはできないため、履歴が無いときはトップへ飛ばすフォールバックを用意しておくと親切です。SPAで戻る・進むを正しく扱うなら pushStatepopstate を組み合わせ、特定URLへの移動が目的なら location を使い分けましょう。