概要

IntersectionObserver とは、ある要素が画面(ビューポート)に見えてきたかどうかを監視するブラウザのAPIである。スクロールイベントを使わずに、要素の表示・非表示を非同期で検知できる。


どんな場面で使われるか

  • ページ下部に近づくと次のコンテンツが自動で読み込まれる(無限スクロール
  • 画像が画面に入ったタイミングで表示される(遅延読み込み / Lazy Load
  • 要素が見えたときにアニメーションが始まる(スクロールアニメーション
  • メッセージが画面に入ったときに既読処理を走らせる(チャットアプリ

従来の方法との違い

scroll イベント IntersectionObserver
仕組み スクロールのたびに位置を計算 見えたときだけ非同期で通知
パフォーマンス 重い(毎回計算が走る) 軽い(ブラウザが最適化)
コード量 多い(位置計算を自分で書く) 少ない(APIに任せる)

従来のやり方(scroll イベント)

// スクロールのたびに計算が走るので重い
window.addEventListener("scroll", () => {
  const element = document.querySelector(".target")
  const rect = element.getBoundingClientRect()
  if (rect.top < window.innerHeight) {
    // 見えた!
  }
})

IntersectionObserver を使ったやり方

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      // 要素が画面に入った!
      console.log("見えた!")
    }
  })
})

observer.observe(document.querySelector(".target"))

主なメソッド

メソッド 意味
observe(要素) 指定した要素の監視を開始する
unobserve(要素) 指定した要素の監視を停止する
disconnect() 全ての監視を停止する

オプション(threshold・rootMargin)

IntersectionObserver にはオプションを渡すことで、通知のタイミングを細かく制御できる。

const observer = new IntersectionObserver(callback, {
  threshold: 0.5,       // 要素が50%見えたら通知
  rootMargin: "100px",  // 画面の100px手前で通知(先読みに便利)
})
オプション 意味
threshold 要素がどれだけ見えたら通知するか(0〜1)
rootMargin 検知範囲を広げる/狭める(CSS風の指定)
root 監視の基準となる要素(デフォルトはビューポート)

実用例:画像の遅延読み込み

const observer = new IntersectionObserver((entries) => {
  entries.forEach(entry => {
    if (entry.isIntersecting) {
      const img = entry.target
      img.src = img.dataset.src  // data-src から本来のURLを設定
      observer.unobserve(img)    // 読み込んだら監視を解除
    }
  })
})

document.querySelectorAll("img[data-src]").forEach(img => {
  observer.observe(img)
})

まとめ

  • 何のため? → 要素が画面に見えたかどうかを効率的に検知するため
  • 従来との違い? → scroll イベントで毎回計算する代わりに、ブラウザが非同期で通知してくれる
  • 主なメソッドは?observe(監視開始)・unobserve(監視停止)・disconnect(全停止)
  • キーワードで覚えるなら? → 「見えたら教えてくれるAPI」

参考文献