ページを離れた際に呼ばれるブラウザイベントについて
ページを離れた際に呼ばれるブラウザイベントについて、共有したくなったので改めて少し調査した上でまとめた。
まとめ
ユーザーがページを離れた際にユーザーの動作をブロックしたいわけでなければvisibilitychange
が最適である。
特にモバイルでの動作を想定している場合、visibilitychange
はホーム画面への移動や画面OFF、別アプリの移動などでも呼ばれるため、ユーザーがページを離れたことを検知するのに適している。
ページの非表示ではなく、ページが実際にアンロードされることを検知したい場合はpagehide
を利用した方が適している。
ユーザーの動作を止めたい場合はbeforeunload
を使うしかないが、iOS Safariでは利用できず、他のモバイル環境で完璧に動作するわけではない。またモバイルでなくても、ユーザーの操作がなければダイアログは表示されない。
unload
は廃止が計画されており利用すべきではない。
動作確認
以降の文章で調査・検証などの表現をしている場合、次のページをChrome 129、Edge 129、Safari 18、iOS Safari 18で動作確認をしている。
https://react-ts-itkkda.stackblitz.io/
このページを2つのタブで開き、片方でページを閉じるなどを行うともう片方にログが送信される仕組みになっている。
大雑把な仕組みは次のようになっている。
const channel = new BroadcastChannel("...");
useEffect(() => {
const controller = new AbortController();
channel.addEventListener("message", saveLogger, {
signal: controller.signal,
});
document.addEventListener("visibilitychange", postLog, {
signal: controller.signal,
});
window.addEventListener("pagehide", postLog, {
signal: controller.signal,
});
window.addEventListener("beforeunload", posyLog, {
signal: controller.signal,
});
return () => {
controller.abort();
};
}, []);
ページを離れた際に呼ばれるブラウザイベント
次のようなイベントが存在する。
beforeunload
pagehide
visibilitychange
unload
ページを閉じようとした場合、上から下の順にイベントが呼ばれる。
詳しくはPage Lifecycle APIを参照。
unload
イベント
利用すべきでない。
- 非推奨かつ廃止が計画されているため利用すべきでない。
- このイベントがリッスンされている場合、BFCacheが妨げられる。
beforeunload
イベント
iOS Safariで動作させたい場合は、機能しない。 積極的に使うべきではなく、ユーザーが入力途中の場合のみイベントリスナーを登録するようにすべき。
- ドキュメントがアンロードされる直前に呼ばれる。
- ページを閉じようとした際にダイアログを表示できる。
- iOS Safariでは利用できない。
- event.preventDefault()を呼ぶことで表示できるようになる。
- event.returnValueに何らかの値を渡す必要はない。
- 検証したところ、無くてもダイアログは表示された。
- 以前はevent.returnValueに文字列を渡すことで任意のメッセージを表示できる環境が存在した。
- 現在は、ブラウザ固有のメッセージを表示することしかできない。
- 現在は、event.returnValue自体が非推奨になっている。
- ユーザーの操作がない場合もダイアログは表示されない。
window.alert()
やwindow.confirm()
などの実行を無視する。- iOS Safariで呼ばれていない。
- Can I useを見ると、イベント自体はサポートしているがevent.preventDefault()による有効化をサポートしていないだけであるように見えるが、実際に検証したところ呼ばれていない。
- ChromeやEdgeなどでは、event.preventDefault()を実行しなくとも呼ばれる。
- このイベントがリッスンされている場合、BFCacheが妨げられる。
- そのため、常にリッスンするような実装は避けるべき。
pagehide
イベント
ページのアンロード時に何かを実行したい場合に適している。
しかし、beforeunload
と異なり、ユーザーが入力中に離脱することを防ぐような使い方は出来ない。
- セッション履歴で現在のページを非表示にすると呼ばれる。
- Chromeで検証したところ、beforeunloadの後に呼ばれていた。
unload
やbeforeunload
のようにBFCacheなどブラウザのキャッシュが妨げられることはない。- そのためページのアンロードを検知する方法としては、最適であるとMDNで紹介されている。
- このイベントは
beforeunload
とは異なり、イベントをキャンセルすることは出来ない。 window.alert()
などの実行は無視される。- 以前Safariで
visibilitychange
にバグがあったため、pagehide
を推奨する記事が多い。
visibilitychange
イベント
ユーザーのセッション終了を検知するイベントとしては最善としてMDNなどでは紹介されている。
beforeunload
と異なり、ユーザーが入力中に離脱することを防ぐような使い方は出来ない。
- ページの表示非表示が切り替わった際に呼ばれる。
- モバイルでは、ホーム画面への移動や画面OFF、別アプリの移動などでも呼ばれる。
- document.visibilityStateまたはdocument.hiddenを利用してページの表示/非表示を識別できる。
window.alert()
などの実行は無視されない。- ただし実行タイミングが異なり、
beforeunload
のダイアログのような使い方は出来ない。 - ページを閉じる場合は実行されず、タブを切り替えた場合は、タブを元に戻すとダイアログが表示される。
- ただし実行タイミングが異なり、
pagehide
と同様に、イベントをキャンセルすることは出来ない。pagehide
と同様に、BFCacheなどブラウザのキャッシュが妨げられることはない。- iOS Safari 14.5以前では、
visibilitychange
がページ遷移時に発火しないバグがあった。- そのためか、
beforeunload
の代わりにpagehide
を推奨する記事が多い。
- そのためか、