小規模サイトの表示速度改善メモ:第6回 bfcacheを妨げない実装で、戻る・進むの体感速度を保つ
「小規模サイトの表示速度改善メモ」第6回は、bfcacheを意識した実装についてです。
今回扱うbfcacheは、ページの初回表示を速くするための施策ではありません。
ただし、ユーザーが一覧ページから詳細ページを開き、また一覧へ戻るような動きをしたとき、bfcacheが効いていれば前のページを再読み込みせずに素早く復元できます。
小規模サイトでも、実装によってはこの復元を妨げてしまうことがあります。初回表示を速くするというより、「本来ブラウザが持っている速さを邪魔しない」ための考え方として整理します。
この記事では、bfcacheそのものの仕組みを詳しく解説するというより、WordPressテーマや小規模サイトのJavaScriptを書くときに、戻る・進むの復元を邪魔しないための実装上の注意点を整理します。
戻るボタンで一瞬で戻れる体験
Webサイトを閲覧していると、一覧ページから詳細ページへ移動し、また一覧ページへ戻る場面はよくあります。
たとえば、次のような動きです。
- お知らせ一覧から、個別のお知らせを開いて戻る
- ブログ一覧から、記事を読んで戻る
- 実績一覧から、実績詳細を見て戻る
- 商品一覧から、商品詳細を確認して戻る
このとき、戻るたびにページを最初から読み込み直すと、表示までに時間がかかります。
特にスマートフォンでは、通信状況や端末性能によって、ほんの少しの待ち時間でも「重い」と感じられやすくなります。また、一覧ページでスクロールしていた位置が自然に復元されないと、ユーザーはもう一度目的の項目を探さなければなりません。
一方で、ブラウザが前のページの状態を保持していれば、戻るボタンを押したときに一瞬で元の画面へ戻れる場合があります。
この体験に関わるのが、bfcacheです。
bfcacheとは何か
bfcache(Back/Forward Cache)とは、ブラウザの「戻る」や「進む」ボタンを押した際に、以前開いていたページの状態をメモリに保存しておき、素早くページを復元する仕組みのことです。
通常のページ読み込みでは、HTML、CSS、JavaScript、画像などを読み込み、必要に応じてJavaScriptの初期化処理も実行されます。
しかし、bfcacheから復元できる場合は、ページをサーバーから再取得したり、最初から再構築したりする必要がありません。以前のページ状態をそのまま復元できるため、非常にスムーズに前のページへ戻れます。
サーバーへのリクエストを行わない場合もあるため、表示が速くなるだけでなく、通信量やサーバー負荷の面でも有利です。
ただし、bfcacheは制作者が明示的に「有効化する」というより、ブラウザが利用できる状態を妨げないことが重要になります。
bfcacheは表示速度改善というより、体感速度を損なわない仕組み
bfcacheは、一度ユーザーが訪問したページに戻るときに効果を発揮する仕組みです。
そのため、初回アクセス時の表示速度を直接改善するものではありません。初めて開くページでは、通常どおりHTMLや画像などを読み込む必要があります。
しかし、「戻る」「進む」ボタンを押したときに一瞬で画面が復元されれば、ユーザーの体感としては非常に速く感じられます。
たとえば、一覧ページから複数の記事を見比べるような場面では、戻るたびに再読み込みが発生するか、すぐに一覧へ戻れるかで体験が大きく変わります。
小規模なCMSサイトや企業サイトでは、初回表示の高速化だけに目が向きがちです。もちろん、画像最適化やページキャッシュも重要です。
ただ、ユーザーは一度ページを開いて終わりではなく、サイト内を行き来します。 その意味で、bfcacheを妨げない実装は、サイト内回遊時の体感速度を保つための施策として考えると分かりやすいです。
unload 依存を避ける
bfcacheを妨げる要因としてよく挙げられるのが、JavaScriptの unload イベントです。
unload は、ページを離れるタイミングで処理を実行するために使われてきました。たとえば、ページを閉じる前に何かを送信する、状態を保存する、といった用途です。
しかし現在では、unload に依存する実装は避けた方がよいとされています。
理由は大きく2つあります。
1つ目は、unload がbfcacheの妨げになる場合があることです。
ブラウザはページをbfcacheに保存したい場合、ページを完全に破棄するわけではありません。そのため、従来の「ページを離れる直前に必ず unload が実行される」という前提が成り立ちにくくなっています。
2つ目は、ブラウザによって挙動が異なり、処理の実行が安定しないことです。
web.devでも、unload の代わりに pagehide を使うことが推奨されています。(web.dev)
ページを離れるときに処理が必要な場合は、まず pagehide を検討します。
window.addEventListener('pagehide', (event) => {
if (event.persisted) {
// ページがbfcacheに保存される可能性がある場合
// 一時停止したい処理などがあればここで扱う
} else {
// 通常のページ離脱
}
});
また、bfcacheから復元されたときにデータの再取得や画面状態の調整が必要な場合は、pageshow を使います。
unload に依存してbfcacheを無効化するのではなく、pagehide と pageshow を使って、ページの離脱時・復元時に必要な処理を分けて考えることが大切です。
戻ったときに状態が残る問題
bfcacheは便利ですが、以前のページ状態を復元する仕組みであるため、戻ったときに状態が残ることがあります。
これはメリットでもあり、注意点でもあります。
たとえば、次のようなケースです。
- バーガーメニューが開いたまま復元される
- モーダルウィンドウが表示されたまま戻ってくる
- ローディング中のクラスが残ってしまう
- ボタンに付けた
disabledが残って操作できない - フォームの入力内容が残る
- 絞り込みやタブ切り替えの状態が残る
- ページ読み込み時に実行していた初期化処理が再実行されない
- アクセス解析のページビューが通常のページ読み込みと同じようには計測されない場合がある
たとえば、リンククリック時にローディング表示を出す実装をしている場合、戻ったときにそのクラスが残っていると、プログレスバーが表示されたままになったり、画面が操作できなくなったりすることがあります。
また、フォーム送信ボタンを二重送信防止のために disabled にした場合、その状態が復元後も残ると、ユーザーが再操作できなくなる可能性があります。
アクセス解析のページビューは、戻る・進むでbfcacheから復元された場合、通常の初回読み込みと同じタイミングで計測タグが再実行されるとは限りません。必要に応じて、復元時の計測方針も確認します。
bfcacheでは、ページが「最初から読み込み直される」とは限りません。 そのため、初回読み込み時だけを前提にしたJavaScriptは、戻る・進む操作で意図しない状態を残すことがあります。
pageshow での復元対応
bfcacheから復元された場合に状態を調整したいときは、pageshow イベントを使います。
pageshow は、ページが表示されるタイミングで発火します。
通常の初回読み込み時だけでなく、ブラウザの戻る・進むによってページが復元されたときにも発火します。(MDN)
特に、bfcacheから復元されたかどうかを見たい場合は、event.persisted を確認します。
window.addEventListener('pageshow', (event) => {
if (event.persisted) {
// bfcacheから復元された場合の処理
}
});
たとえば、戻ってきたときにローディング状態を解除したい場合は、次のようにします。
window.addEventListener('pageshow', () => {
document.documentElement.classList.remove('is-loading');
document.documentElement.classList.remove('is-navigating');
document.querySelectorAll('[disabled][data-reset-disabled]').forEach((element) => {
element.disabled = false;
});
});
また、バーガーメニューやモーダルの状態を戻したい場合は、復元時に閉じる処理を入れておくと安全です。
window.addEventListener('pageshow', (event) => {
if (!event.persisted) {
return;
}
document.documentElement.classList.remove('is-menu-open');
document.documentElement.classList.remove('is-modal-open');
document.querySelectorAll('.js-modal.is-open').forEach((modal) => {
modal.classList.remove('is-open');
});
});
ただし、何でも初期化すればよいわけではありません。
たとえば、一覧ページのスクロール位置や、ユーザーが入力途中だったフォーム内容は、残っていた方が便利な場合もあります。 bfcacheは、ユーザーが直前まで見ていた状態を素早く復元する仕組みです。
そのため、復元時の対応では、次のように考えるとよいです。
- 残っていた方が自然な状態は、そのまま残す
- 操作不能や誤表示につながる状態だけ解除する
- 最新データが必要な箇所だけ再取得する
- 初回読み込み時の処理に依存しすぎない
bfcache対応は、単に「戻ったら全部リセットする」ことではありません。 復元された状態を前提に、必要な部分だけ整えることが重要です。
bfcacheが効いているか確認する
bfcacheは、コードを書いただけで終わりではなく、実際のブラウザで戻る・進むを試して確認することが大切です。
Chromeの場合は、DevToolsのApplicationパネルにある Back/forward cache の確認機能を使うと、ページがbfcacheに保存できるか、保存できない場合は何が原因かを確認できます。
また、実際の確認では次のような操作を見ます。
- 一覧ページから詳細ページへ移動し、戻る
- 戻ったときにスクロール位置が自然に復元されるか
- メニューやモーダルが開いたままにならないか
- ローディング表示や
disabledが残らないか - フォーム入力中のページで、残るべき内容と解除すべき状態が整理できているか
特にスマートフォンでは、PCと挙動が異なる場合があります。PCブラウザだけでなく、iPhone SafariやAndroid Chromeでも戻る・進むの挙動を確認しておくと安心です。
なお、Basic認証がかかった検証環境などでは、Chrome DevToolsのBack/forward cacheテストが使えない場合があります。テスト環境で「使用不可」と表示された場合は、実装だけでなく、認証やレスポンスヘッダー、拡張機能などの影響も含めて確認するとよいでしょう。
WordPressサイトで気をつけたいこと
WordPressで作られた小規模サイトでも、bfcacheは関係します。
特に、次のようなサイトでは意識しておくとよいです。
- お知らせ一覧と詳細ページがある
- ブログ記事一覧と詳細ページがある
- 実績一覧や商品一覧がある
- 採用情報一覧から募集要項詳細へ移動する
- JavaScriptでメニュー、モーダル、タブ、絞り込みを制御している
- フォーム送信時にボタンの二重送信防止をしている
WordPressサイトでは、ページごとに大きなアプリケーションを作っていなくても、テーマやプラグインがJavaScriptで画面状態を変更していることがあります。 自作したJavaScriptだけでなく、テーマ付属のメニュー制御、フォームプラグイン、ポップアップ系プラグイン、絞り込みUIなどが、bfcache復元時にどのような状態になるかも確認しておく必要があります。
たとえば、次のような処理です。
- バーガーメニューの開閉
- スマホナビゲーションの表示
- 検索フォームの開閉
- アコーディオン
- タブ切り替え
- モーダル表示
- フォーム送信ボタンの無効化
- ローディング表示
- スムーススクロール
- 絞り込みUI
これらは通常のページ読み込み時には問題なく動いていても、bfcacheで復元されたときに状態が残ると、意図しない表示になることがあります。
そのため、WordPressテーマや独自JavaScriptを書くときは、次の点を意識しておくと安全です。
unload に依存しない
ページ離脱時の処理を unload に置かないようにします。
必要であれば、pagehide や visibilitychange を検討します。
戻ったときに残って困るクラスを整理する
たとえば、次のようなクラスは復元時に解除対象になることがあります。
is-loading
is-navigating
is-menu-open
is-modal-open
is-submitting
ただし、すべてを機械的に消すのではなく、サイトのUIに合わせて判断します。
フォーム送信ボタンの disabled に注意する
二重送信防止のために送信ボタンを無効化する実装はよくあります。
しかし、bfcache復元時に disabled が残ると、戻ったユーザーが再送信や修正をできなくなる可能性があります。
必要であれば、対象のボタンに属性を付け、pageshow で解除します。
<button type="submit" data-reset-disabled>
送信する
</button>
window.addEventListener('pageshow', (event) => {
if (!event.persisted) {
return;
}
document.querySelectorAll('[data-reset-disabled]').forEach((button) => {
button.disabled = false;
});
});
最新データが必要なページは慎重に扱う
通常の企業サイトやブログでは、bfcacheで多少古い状態が復元されても大きな問題にならないことが多いです。
一方で、会員ページ、予約状況、在庫、ログイン状態、決済関連など、最新状態が重要なページでは注意が必要です。
その場合でも、安易にbfcacheを無効化するのではなく、復元時に必要な箇所だけ再取得する、キャッシュ対象外にすべきページを分ける、といった設計が必要です。
まとめ
bfcacheは、ページの初回表示を速くする仕組みではありません。
しかし、ブラウザの戻る・進む操作で前のページを素早く復元できるため、サイト内を行き来するときの体感速度に大きく関わります。
小規模なCMSサイトや企業サイトでも、一覧ページと詳細ページを行き来する場面は多くあります。 そのため、bfcacheを妨げないことは、ユーザーにとって自然で快適な閲覧体験につながります。
制作時には、次の点を意識しておくとよいです。
- bfcacheは「有効化する」より「邪魔しない」ものとして考える
unloadに依存しない- ページ離脱時の処理は
pagehideを検討する - 復元時の調整には
pageshowを使う - 戻ったときに残ると困る状態だけを解除する
- すべてを初期化せず、残る方が自然な状態は残す
- WordPressテーマやフォーム周りのJavaScriptでも復元時の挙動を確認する
表示速度改善というと、画像軽量化やキャッシュ設定に目が向きがちです。
もちろんそれらは重要ですが、ブラウザが本来持っている高速な復元機能を妨げないことも、体感速度を守るうえでは大切です。
小規模サイトでは、大がかりな高速化だけでなく、こうした実装上の小さな配慮も積み重ねていくことが重要です。
シリーズ記事
- 小規模サイトの表示速度改善メモ:第1回 WordPressを毎回動かさないためのキャッシュの考え方
- 小規模サイトの表示速度改善メモ:第2回 まず見直したい画像最適化の基本
- 小規模サイトの表示速度改善メモ:第3回 ファーストビューに重い機能を詰め込まない
- 小規模サイトの表示速度改善メモ:第4回 外部タグ・計測タグは、入れるほどサイトが重くなる
- 小規模サイトの表示速度改善メモ:第5回 共用サーバでCDNやサーバーキャッシュを使うときの注意点
- 小規模サイトの表示速度改善メモ:第6回 bfcacheを妨げない実装で、戻る・進むの体感速度を保つ(←この記事)
