Intersection Observer APIのメモ
どんなAPIか
要素がビューポート(または指定した親要素)に入った/出たを非同期で検知するAPIです。
Reactで useEffect に scroll イベントを貼って位置計算するより、パフォーマンスも高く安定した挙動になります。
ほとんどのブラウザでサポートされているので、安心して使えます。 (IE11以前は非対応ですが…もう気にしなくていいはず…泣)
This feature is well established and works across many devices and browser versions. It’s been available across browsers since March 2019
基本の使い方
new IntersectionObserver(callback, options) でオブザーバーを作り、.observe(element) で監視開始します。コールバックの entry.isIntersecting で要素が見えているかを判定できます。
よくあるユースケース
- 遅延読み込み — 画像や3Dモデルなどをビューポート付近でロード、通過後にアンロード
- 利用ライブラリ例: model-viewer(3Dモデルのビューポート検知)
- スクロール連動アニメーション — 要素が画面に入ったタイミングでフェードインなど
- 利用ライブラリ例: Motionの
whileInView、Locomotive Scroll(Lenisベース)
- 利用ライブラリ例: Motionの
- 無限スクロール — リスト末尾の要素を監視して追加読み込みを発火
- 利用ライブラリ例: react-infinite-observer
- セクション検知 — 目次のハイライトや、現在表示中のセクションの判定に
- 利用ライブラリ例: Fumadocs TOC(このブログの目次でも採用)
このブログでも、各種コンテンツの埋め込みで利用しています。例えば以下のような埋め込みツイートや3Dモデルが多いページでは、このAPIがないとモバイルSafariでクラッシュしてしまいます。このAPIのおかげでクラッシュせずに済んでいます!
rootMargin が便利
ビューポートの外側(手前)から検知を開始できます。例えば 200px を指定すると、要素が画面に入る200px前にコールバックが発火するので、スクロールが到達する頃には読み込みが完了しています。
const observer = new IntersectionObserver(callback, {
rootMargin: "200px", // ビューポートの200px外側から検知
});最適な値はコンテンツの種類や状況によって異なります。実際のコードを見ると、画像の遅延読み込みでは 50px 程度を使う例がある一方、model-viewerの3Dモデル描画では画面外のアニメーションが描画を圧迫する問題から 0px に設定されているようです。(Claude調べ)
ちなみに <img loading="lazy"> などの遅延読み込みでは、Chromeが内部で持つしきい値が4G回線で1250px、3G以下で2500pxとかなり大きめのようです。
Reactでの使い方
React環境だと、react-intersection-observer の useInView がとても使いやすいです。
メンテナンスも活発で、バージョンはv10に達しており、最終更新も1ヶ月前です。(2026年2月18日現在)
import { useInView } from "react-intersection-observer";
function LazyComponent() {
const { ref, inView } = useInView({
triggerOnce: true, // 一度だけ発火(遅延読み込み向き)
rootMargin: "200px", // 手前で読み込み開始
});
return (
<div ref={ref}>
{inView ? <HeavyContent /> : <Skeleton />}
</div>
);
}triggerOnce: true にすると内部で unobserve() してくれるので、一方向の遅延読み込みはこれだけで完結します。
参考
VRが好きなWebエンジニア。WebXRやVR・機械加工などの技術が好きでものづくりしている。WebXR JPというコミュニティやWeb技術集会というVR空間内の技術イベントを運営中。
コメント
この記事についてのご意見・ご質問をお気軽にどうぞ