
この記事ではIntersectionObserverの使い方を紹介していきたいと思います。
IntersectionObserverってなに?
Intersection 交差点
observer 監視
その名の通り交差を監視するAPIのことです。
See the Pen Untitled by yokotamaki (@yokotamaki) on CodePen.
要素が入るとふわっと出てくるようなアニメーションよく見かけるかと思います。
scrollイベントを使って記述することができますが、scrollイベントはスクロールするたびに実行されるのでパフォーマンスがよくありません。
ですがIntersectionObserverは非同期でそんな心配がなく、シンプルでとってもわかりやすく実装することができます。
解説① / IntersectionObserver の呼び出しを確認する
まずは基本となる仕組みをおさえておきましょう!
動画のようにalertを使って、IntersectionObserverの実行のタイミングを確認していきます。
const io = new IntersectionObserver(コールバック関数);
io.observe(監視対象の要素);
IntersectionObserver オブジェクトを作成し、交差時に実行するコールバック関数を渡しています。そして observe メソッドで監視したい要素を指定することで監視を開始することができます。
const target = document.querySelector(".target"); //監視対象を取得
const callback = function() {
alert("呼び出しています!"); //実行時の処理
}
const io = new IntersectionObserver(callback); //初期化
io.observe(target); //監視を開始
① 監視対象の要素を querySelector で取得
②IntersectionObserver実行時のコールバック関数を記述
③IntersectionObserverの初期化(引数にコールバック関数を指定する)
④observeメソッドで監視を開始
画面に入った時、画面の外に出た時に実行されたのが確認できたかと思います。これがデフォルトで設定されています。
動画のコード
<div class="wrapper">
<div class="elm"></div>
</div>
.wrapper {
height: 200vh;
width: 100%;
background-color: #dfdfdf;
}
.elm {
width: 250px;
height: 250px;
position: absolute;
left: 50%;
top: 300px;
transform: translateX(-50%);
background-color: orange;
}
const elm = document.querySelector(".elm");
const callback = function() {
alert("呼び出しています!");
}
const io = new IntersectionObserver(callback);
io.observe(elm);
解説② / 条件分岐で処理を分ける
もう少し細かく見ていきましょう。
条件分岐で画面の中に入った時、画面の外に出た時で処理を分けていきます。
const elm = document.querySelector(".elm");
const callback = function(entries, observer) {
entries.forEach(entry => { //追加
if (entry.isIntersecting) { //追加
alert("要素が画面の中に入りました"); //追加
} else { //追加
alert("要素が画面の外に出ました"); //追加
}
})
}
const io = new IntersectionObserver(callback);
io.observe(elm);
条件分岐をするときは.isIntersecting を使います。 isIntersecting は監視対象の要素が交差しているかを確認するプロパティでbool値で返してくれます。
そしてIntersectionObserver は複数の要素を監視することができ、各要素が画面の中に入った時、外側に出た時にcallback関数が呼び出されます。entryiesに複数の要素が格納されているためEach分を使っていきます。
callback・・・交差時に実行したい関数(処理)
elm・・・監視対象の要素
entries・・・監視対象の要素(複数)
entry・・・監視対象の要素(1つ)
isIntersecting・・・交差しているか確認するプロパティ(交差していればtrue)
一度画面に入った要素の監視をとめたい場合
const elm = document.querySelector(".elm");
const callback = function(entries, observer) {
entries.forEach(entry => {
if (entry.isIntersecting) {
alert("要素が画面の中に入りました");
bserver.unobserve(entry.target); //追加
} else {
alert("要素が画面の外に出ました");
}
})
}
const io = new IntersectionObserver(callback);
io.observe(elm);
entryのtargetに要素が格納されています。bserver.unobserve(entry.target); を追加することで監視をとめることができるので、一度alertが表示されたら出てこなくなるかと思います。
解説③ / オプションを理解する
最後にオプションについて解説していきます。
IntersectionObserver にはオプションというものがあります。
解説①②で画面に入ったタイミング、外に出たタイミングで実行さるのが確認できたかと思いますが、それではちょっと不便ですよね…
オプションを付けることで監視を開始するタイミングを指定することができます。
下の動画は赤い要素に入った時に監視対象の要素の色が変わるように実装したものです。
オプションを3つ紹介します。
root
監視するベースとなる要素を指定します。
初期値はビューポート(表示されている画面領域のこと)です。
rootMargin
rootからののmargin(距離)を指定します。
指定の仕方は上右下左(”10px 20px 0px 10px”)とmarginと同じように指定できますが、0の場合でもpxを付けないのエラーになってしまうので注意が必要です。
threshold
監視対象の要素がrootにどれくらい入ったらコールバック関数が呼ばれるかを指定します。
指定の仕方は0~1の値です。指定が1なら100%入ってきたら、デフォルト値は0で監視対象の要素が少しでも入ってきたら実行されます。
説明だけだとイメージが付きにくいかと思うので図を用意しました。

//追加
const options = {
root: null,
rootMargin: "-200px -100px",
threshold: 0
};
const elm = document.querySelector(".elm");
const callback = function(entries, observer) {
entries.forEach(entry => {
if(entry.isIntersecting) {
entry.target.classList.add("show");
} else {
entry.target.classList.remove("show");
}
});
}
const io = new IntersectionObserver(callback, options); //追加
io.observe(elm);
オプションを指定する際はIntertsectionObserverオブジェクトを作成する際の第2引数にoptionsを渡してあげることで適用されます。
動画のコード
<div class="wrapper">
<div class="elm"></div>
<div class="box-a">
<div class="box-b"></div>
</div>
</div>
/* 画面に入った時に追加される */
.elm.show {
background-color: red;
}
.wrapper {
height: 300vh;
width: 100%;
background-color: #dfdfdf;
}
.elm {
width: 100px;
height: 100px;
position: absolute;
left: 50%;
top: 120vh;
transform: translateX(-50%);
background-color: orange;
}
.box-a {
padding: 200px 100px;
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
.box-b {
background-color: rgba(255, 0, 0, 0.116);
border: 5px dashed red;
width: 100%;
height: 100%;
}
const options = {
root: null,
rootMargin: "-200px -100px",
threshold: 0
};
const elm = document.querySelector(".elm");
const callback = function(entries, observer) {
entries.forEach(entry => {
if(entry.isIntersecting) {
entry.target.classList.add("show");
} else {
entry.target.classList.remove("show");
}
});
}
const io = new IntersectionObserver(callback, options);
io.observe(elm);