タブの切り替えを検知する visibilitychange イベント
Webアプリケーションの開発において、ユーザーが現在そのページを見ているか(アクティブ)、別のタブを開いているか(非アクティブ)を判別したいケースがあります。
例えば、非アクティブ時には定期的なデータ通信(ポーリング)や高負荷なアニメーションを停止し、アクティブに戻ったタイミングで再開させることで、クライアントのリソース消費を抑えることができます。
本記事では、タブの表示状態を検知するJavaScriptの「visibilitychange イベント」の仕様と基本的な実装方法について解説します。
visibilitychange イベントの概要
visibilitychange イベントは、ドキュメントの表示状態(可視性)が変化した際に document オブジェクトに対して発火します。
現在の状態は document.visibilityState プロパティで取得可能です。主な値は以下の通りです。
visible: ページが表示されている状態(アクティブ)。hidden: ページが非表示の状態(別タブを表示中、またはブラウザが最小化されている)。
基本的な実装コード
document に対してイベントリスナーを設定し、visibilityState や hidden の値を判定して処理を分岐させます。
以下は、タブの状態に応じて音声や動画の再生状態を制御するサンプルコードです。
document.addEventListener("visibilitychange", () => {
if (document.hidden) {
// 非表示になる瞬間に再生中だったかを記録 (!audio.paused が true なら再生中)
playingOnHide = !audio.paused;
audio.pause(); // 音声を停止
} else {
// タブが表示状態に戻った時
// 音声が "playing on hide"(隠れる前は再生中)であった場合は復旧する
if (playingOnHide) {
audio.play();
}
}
});
このロジックを実装することで、ユーザーがタブを離れた(非表示になった)際は自動的に一時停止し、戻ってきたら「元々再生中だった場合のみ」再開させるという、気が利いた挙動を実現できます。
主な活用シーン
このイベントは主に、パフォーマンスの最適化とUX(ユーザー体験)の制御に使用されます。
1. リソース消費の抑制
ユーザーが見ていないページでCPUやネットワーク帯域を消費し続けるのは非効率です。以下のような処理は、hidden 状態で一時停止することを推奨します。
- リアルタイム情報の定期取得(ポーリング)
- CanvasやCSSによる高負荷なアニメーション
- 自動で切り替わるスライドショー(カルーセル)
2. コンテンツの制御
動画や音声コンテンツを含むサイトでは、タブが非表示になったタイミングで再生を一時停止することで、意図しない音声の垂れ流しを防ぎます。
blur / focus イベントとの違い
類似するイベントに window.blur と window.focus がありますが、これらは「ウィンドウ全体のフォーカス」を検知します。
blur/focus: ユーザーがブラウザから別のアプリケーションへ切り替えた際にも発火します。visibilitychange: ブラウザ内で「タブ」が切り替わった状態を正確に検知できます。
Webブラウザ上のタブの管理においては、visibilitychange の使用が適切です。
まとめ
visibilitychange イベントを利用することで、ページの表示状態に応じた適切なリソース管理が可能になります。
不要な処理を制御することは、ユーザーの端末負荷軽減につながり、結果としてWebサイトの品質向上に寄与します。要件に応じて実装をご検討ください。
よくある質問(FAQ)
すべてのブラウザで動作しますか?
はい。Chrome、Firefox、Safari、Edgeなど、主要なモダンブラウザで標準サポートされています。安心して実務で使用可能です。
タブを閉じたことは検知できますか?
visibilitychange は「非表示」への遷移を検知しますが、「閉じる」操作そのものを特定するものではありません。ただし、タブを閉じる際も状態は hidden になるため、終了直前の処理として活用されるケースはあります。より厳密な終了検知には pagehide イベントなどの併用が検討されます。
動画の自動再生・停止制御における注意点は?
タブ非表示時に動画を停止(pause)することは可能ですが、再表示時に自動で再生(play)する挙動は、ブラウザの自動再生ポリシーによりブロックされる場合があります。再開処理を実装する際は、ブラウザごとの挙動検証が必要です。