タイトル: History API
SEOタイトル: HTML5 History API(pushState / popstate / SPA ルーティング)完全ガイド
| この記事の要点 |
|
History API とは
HTML5 History API は、ブラウザの戻る/進む履歴を JavaScript から操作する API です。ページをリロードせずに URL を変更できるため、SPA(Single Page Application)のルーティング機構の中核として広く使われています。Vue Router、React Router、Next.js Client Router、SvelteKit などのフレームワークも内部では History API を呼んでいます。
主要メソッド一覧
| API | 動作 | 履歴に追加 |
|---|---|---|
history.pushState(state, title, url) | 新エントリ追加 | ○ |
history.replaceState(state, title, url) | 現エントリを置換 | × |
history.back() | 1 つ戻る(戻るボタン同等) | - |
history.forward() | 1 つ進む | - |
history.go(n) | n エントリ移動(負数で戻る) | - |
history.length | 現セッションの履歴数 | - |
history.state | 現エントリの state オブジェクト | - |
history.scrollRestoration | 戻り時のスクロール位置復元(auto/manual) | - |
pushState / popstate の最小例
<nav>
<a href="/home" data-link>Home</a>
<a href="/about" data-link>About</a>
</nav>
<main id="view">Home Page</main>
<script>
function render(path) {
document.getElementById('view').textContent = path + ' Page';
}
// リンククリックで pushState
document.querySelectorAll('[data-link]').forEach(a => {
a.addEventListener('click', (e) => {
e.preventDefault();
const url = a.getAttribute('href');
history.pushState({ path: url }, '', url);
render(url);
});
});
// 戻る/進むで popstate
window.addEventListener('popstate', (e) => {
const path = (e.state && e.state.path) || location.pathname;
render(path);
});
</script>
pushState と replaceState の違い
| 用途 | 選択 |
|---|---|
| 通常のページ遷移 | pushState |
| クエリ更新(フィルタ変更等)で戻る対象にしたくない | replaceState |
| ログイン後のリダイレクト(ログイン画面を履歴に残さない) | replaceState |
| モーダルの開閉を URL に反映 | 状況次第(戻るで閉じたいなら pushState) |
location.hash 方式との比較
// 古典: ハッシュベース(HTML5 以前)
location.hash = '#/about';
window.addEventListener('hashchange', () => {
console.log(location.hash);
});
// URL: https://example.com/#/about
// モダン: History API
history.pushState(null, '', '/about');
// URL: https://example.com/about
| 比較 | hash 方式 | History API |
|---|---|---|
| URL 見た目 | # 入りで不格好 | 通常 URL でクリーン |
| SEO | 通常クロール対象外 | SSR / プリレンダリングで対応可 |
| サーバ設定 | 不要 | ★ 全パスを index.html へフォールバックが必要 |
| 古い IE 対応 | IE6+ で動く | IE10+ |
SPA フォールバックの設定例
History API で /about という URL に切り替えても、ブラウザをリロードするとサーバが本当に /about を返そうとして 404 になります。これを防ぐためサーバで「全パスを index.html に返す」設定を入れます。
# Nginx
location / {
try_files $uri $uri/ /index.html;
}# Apache (.htaccess)
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]// Express
const path = require('path');
app.use(express.static('dist'));
app.get('*', (_req, res) => {
res.sendFile(path.join(__dirname, 'dist', 'index.html'));
});
URL / URLSearchParams との連携
// 現在の URL からクエリ取得
const params = new URLSearchParams(location.search);
const page = params.get('page') || '1';
// クエリだけ書き換え(履歴に追加せず replace)
params.set('page', '2');
history.replaceState(null, '', '?' + params.toString());
// URL オブジェクトで安全に組み立て
const url = new URL(location.href);
url.pathname = '/items';
url.searchParams.set('sort', 'asc');
history.pushState(null, '', url);
scrollRestoration
「戻る」操作で前ページのスクロール位置を復元するかをコントロールできます。SPA では自前で復元したい場合があるので manual にする運用が一般的です。
if ('scrollRestoration' in history) {
history.scrollRestoration = 'manual';
}
// 自前でスクロール位置を保存
window.addEventListener('beforeunload', () => {
sessionStorage.setItem('scroll:' + location.pathname, scrollY);
});
window.addEventListener('load', () => {
const y = sessionStorage.getItem('scroll:' + location.pathname);
if (y) window.scrollTo(0, +y);
});
Router フレームワークの内部
| フレームワーク | History API の使い方 |
|---|---|
| Vue Router (createWebHistory) | history.pushState + popstate リスナ |
| React Router (BrowserRouter) | history パッケージ経由で History API |
| Next.js App Router | 独自 Router、Soft Navigation に History API |
| SvelteKit | fetch + History API + クライアントナビ |
| Astro View Transitions | History API + ViewTransition API |
FAQ
Q: pushState の第 2 引数 title は何を入れる?
A: ほとんどのブラウザで無視されます。空文字 "" で OK。document.title を別途代入してください。
Q: popstate が pushState 直後にも発火する?
A: 発火しません。popstate はユーザの戻る/進む操作と history.back() 等のメソッド呼び出しでのみ発火します。
Q: 別オリジンに pushState できる?
A: できません。同一オリジン内のパス変更のみ許可。クロスオリジンは location.href 代入で通常遷移。