Intersection Observer 入門|スクロールに応じた処理をデモで直感的に理解しよう!

Web制作の現場で、「ある要素が画面内に入ったらアニメーションを開始する」や「特定のエリアが表示されたらデータを読み込む」といった、スクロールに応じた処理を加えるケースはよくあります。
こうした処理は、かつては scroll
イベントを使って実装されるのが一般的でしたが、手間がかかる上に、パフォーマンスの面でも課題がありました。
そうした課題を解決してくれるのが Intersection Observer です。
Intersection Observer を使えば、特定の要素がいつ・どのくらい画面内に入ったかを簡潔に、しかも効率的に判定できます。すでに主要なブラウザでは広くサポートされており、現場でも十分に実用レベルの技術になっています。

自分も普段のコーディングでよく使っています!とくにスクロールアニメーションや遅延読み込みなど、以前は scroll
イベントで頑張っていた処理も、今では Intersection Observer に任せることが増えています。
この記事では、Intersection Observer の基本的な使い方を解説しつつ、特に重要なパラメータである rootMargin
や threshold
については、スクロールしながら視覚的に理解できるデモを用意しています。
「この値を変えると、どう変わるのか?」
「どのくらい見えたら発火するのか?」
といった疑問を、実際に試しながらその場で体感できる構成にしているので、これまで仕組みが曖昧だった方にも、自信を持って使いこなせるようになるはずです。
- Intersection Observer の仕組みをしっかり理解したい方
scroll
イベントとの違いや使い分けに悩んでいる方rootMargin
やthreshold
の挙動を視覚的に理解したい方- 実務で使える書き方を知りたい方
Intersection Observer とは?
Intersection Observer(インターセクション・オブザーバー)は、ある要素が画面内に入ったかどうかを、簡単かつ効率的に検出できる API です。
これまでは「スクロールに応じてアニメーションを始めたい」や「画面に入ったら画像を読み込みたい」といった処理を行うには、scroll
イベントを使って位置を計算するのが一般的でした。でも、これにはスクロールごとに位置をチェックする手間があり、処理が重くなったり、コードが複雑になりがちでした。
そこで便利なのが Intersection Observer。対象の要素が画面に入った・出たときなど、タイミングを指定して処理を実行することができます。位置の計算は不要、監視の対象も複数同時にOK。ブラウザ側で最適化されているので、軽くて正確というのが大きな魅力です。


たとえば「画像が表示されたら読み込みを開始する」「特定の要素が半分見えたらクラスを付ける」といった処理も、ほんの数行で実現できますよ!
scrollイベントとの比較
Intersection Observer を知るうえで外せないのが、これまで主流だった scroll
イベントとの違いです。
scrollイベントでの実装
スクロールに応じてアニメーションを始めたり、画像を読み込んだりしたいとき、以前はこんなコードを書くのが一般的でした。
window.addEventListener('scroll', () => {
const target = document.querySelector('.target');
const scrollY = window.scrollY;
const windowH = window.innerHeight;
const targetTop = target.getBoundingClientRect().top + scrollY;
if (scrollY + windowH > targetTop) {
// 要素が画面内に入ったときの処理
}
});
このように、毎回スクロールのたびに「現在のスクロール位置」「画面の高さ」「要素の位置」などを計算して、条件を判定する必要があります。
一見シンプルですが、対象の要素が増えると処理が重くなりやすく、スマホではカクついたり、コードが複雑になって管理しづらいという欠点があります。
Intersection Observer なら?
Intersection Observer を使えば、「どの要素が、どんな条件で見えるようになったら反応するか」を指定しておくだけで、複雑な判定ロジックなしに処理を分けられます。
- スクロール位置の計算 → 不要
- 処理の最適化 → ブラウザ任せでOK
- コード → スッキリ書ける
というわけで、パフォーマンス的にも保守性の面でもとても優れた選択肢になります。
どちらを使うべきか?
もちろん、すべての場面で Intersection Observer がベストというわけではありません。ざっくりとした使い分けのイメージは以下の通りです。
API | 主な用途 | 例 |
---|---|---|
Intersection Observer | 要素が画面内に「入った瞬間」「出た瞬間」など、“境界をまたいだ”タイミングを検知したいとき | ・アニメーションのトリガー ・遅延読み込み(画像・データ) ・セクションの表示通知 など |
scrollイベント | 「スクロール量」や「スクロール進行度」に応じて、連続的に状態を変化させたいとき | ・パララックス効果 ・スクロールに合わせて背景色やサイズを変える ・スクロールインジケーター(進行バー)など |
それぞれ得意な用途があるので、目的に応じて使い分けるのがポイントです。

自分はまず「Intersection Observer でできるか?」を考えて、それが難しいときに scroll イベントを使うようにしています!
基本的な使い方
Intersection Observer は、以下のような流れで使います。
- 監視対象の要素を選ぶ
IntersectionObserver
を生成する- 監視を開始する(observe)
実際のコードはこんな感じです。
const target = document.querySelector('.target');
const observer = new IntersectionObserver((entries) => {
entries.forEach((entry) => {
if (entry.isIntersecting) {
// 要素が見えたら実行する処理
entry.target.classList.add('is-visible');
}
});
});
observer.observe(target);
このコードでやっていること
.target
というクラスの要素を監視対象として取得します。IntersectionObserver
を生成し、その中で「発火したときの処理」を定義しています。observe()
メソッドで、対象の要素を監視状態にしています。
ポイントは、entry.isIntersecting
が true
のとき、要素が画面に入ったことを意味するということ。この瞬間にクラスを付けたり、画像を読み込んだり、アニメーションを始めたりすることができます。

ちなみに、画面から消えたときは isIntersecting
が false
になるので、クラスを外したり、非表示に戻したりする処理も簡単に書けます。
各種オプションも指定可能
先ほどのコードでは、オプション(第二引数)を省略していましたが、以下のように root
、rootMargin
、threshold
を指定することで、監視条件を細かく調整できます。
const options = {
root: null,
rootMargin: '0px 0px -100px',
threshold: 0.5
};
const observer = new IntersectionObserver((entries) => {
// ...
}, options);
root とは?
root
は「どこを基準に画面内とみなすか」を決めるオプションです。通常は null
を指定して、ビューポート(画面全体)を基準にすることが多いです。
ただし、特定の要素内でスクロールを監視したい場合などは、その要素を root
に指定することもできます(たとえば overflow: scroll
などでスクロール可能な要素)。
const options = {
root: document.querySelector('.scroll-area'),
rootMargin: '0px',
threshold: 0.5
};
このようにすれば、.scroll-area
内でのスクロールに対して、Intersection Observer が発火します。
次のセクションからは、rootMargin
と threshold
の使い方を、スクロール連動のデモ付きで詳しく解説していきます!
rootMargin の詳細解説
rootMargin
は、監視の境界線(ビューポート)を拡張または縮小するためのオプションです。指定できる値は CSS の margin
と同じ形式で、例えば 100px 0px -100px 0px
のように上下左右を指定できます。
一見するとわかりづらいのですが、rootMargin
は「画面に見え始めるタイミング」を調整する役割があります。たとえば、下方向に rootMargin: 100px
を設定すると、要素が画面内にまだ見えていなくても、100px 手前で発火します。要素が実際に見えているかどうか、というよりは「監視の境界線がどこにあるか」を操作しているイメージです。
デモを試してみる
実際にどのようなタイミングで発火するのかは、言葉より動きを見たほうが早いです。以下のデモでは、「上方向」「下方向」の rootMargin
を自由に切り替えられます。条件を満たすと監視対象の要素が色付きで反応するので、値を変えながらスクロールして確かめてみてください。
rootMargin のデモ
OFFON
rootMargin のデモ
これが監視対象の要素です
現在の rootMargin
rootMargin: '0px 0px 0px'
発火する条件
- この要素が、画面の上から 0px
- この要素が、画面の下から 0px
スクロールしていくと、監視対象の要素に色が付き、画面右端(スマホでは右上)に「ON」と表示されます。この状態が「isIntersecting
が true になった」=「発火した」タイミングです。
さらに、説明欄には「何px・何% 見えたら発火するか」が表示されるので、値を変えながら動きを試すことで、rootMargin
のしくみを感覚的に理解できるはずです。ぜひ試してみてください!
パターン例
rootMargin: '0px 0px -200px'
→ 画面の下から200px以上見えたときに発火します。通常よりも発火タイミングが遅くなるため、要素がある程度見えたことを条件に処理したい場合に使えます。rootMargin: '-50% 0px 0px'
→ 要素の上端が画面内に少しでも入ったらONになり、下端が画面の中央を超えるとOFFになります。アニメーションをすぐに開始し、ある程度画面を通り過ぎたらOFFにしたいときに便利です。
rootMargin
を使うと、「いつ発火するか」の境界線を好きな位置にずらせるようになります。見せ方の工夫にぜひ使ってみてください。
threshold の詳細解説
threshold
は、「要素がどのくらい見えたら発火するか」を指定するオプションです。値は 0
〜1
の間の小数で、要素の表示領域がどれだけ画面に入っているかの割合を意味します。
たとえば、以下のような具合です。
threshold: 0
→ 少しでも見えたら 発火(デフォルト値)threshold: 0.5
→ 半分見えたら 発火threshold: 1
→ すべて見えたら 発火

rootMargin
が画面基準だとしたら、threshold
は要素基準で発火を判断する感じですね!
デモを試してみる
以下のデモでは、threshold
の値を切り替えながら、発火タイミングの違いを試すことができます。監視対象の要素が条件を満たすと色が変わり、画面右端(スマホでは右上)の表示が「ON」になります。どの値でどう変わるか、実際にスクロールしながら確かめてみてください。
threshold のデモ
OFFON
threshold:
threshold のデモ
これが監視対象の要素です
現在の threshold
threshold: 0
発火する条件
- この要素が少しでも見えたとき
パターン例
threshold: 0
→ 要素がほんの少しでも画面に入ったら即発火。ユーザーに「見えた瞬間」に何かを起こしたいときに便利です。threshold: 1
→ 要素がすべて見えたときにだけ発火。確実に表示されたあとで何かを実行したいときに便利です。threshold: 0.5
→ 要素の半分が表示された時点で発火。ある程度表示されてから処理を行いたいときに向いています。
threshold
をうまく使えば、「少し見えただけで動かすか? それとも完全に見えてからにするか?」といった見せ方の細かい調整ができます。アニメーションや画像の読み込みタイミングの最適化など、実務でも出番の多いプロパティです。
まとめ
Intersection Observer を使えば、「要素が見えたら何かする」という処理を、シンプルに・効率よく書くことができます。主要なブラウザで問題なく使えるので、現場でも当たり前に使われる手法になっています。
今回のデモを動かしてみながら、ぜひご自身のコーディングにも取り入れてみてください!
押していただけると励みになります!