Intersection Observerの使い方!時間差スクロールイベントのサンプル付き
posted : 2021.01.11
こんにちは、ma-ya’s CREATE[まーやずくりえいと]です。
スクロールイベントはかなり実装したくなっちゃうタイプです。
やはりサイトがリッチに見えるし、何よりいい感じに視線誘導が出来ればUI的にも嬉しいもんですよね。
スクロールイベントは実装したい。でもパフォーマンスの低下が心配…
普通に実装するとしたら↓のような感じになるでしょう。
jQuery
$(window).on('scroll',function(){ //ここに処理 })
vanilla.js
window.addEventListener('scroll', function(){ //ここに処理 })
まあブラウザやPC、ネットワークのパフォーマンスが向上している昨今はそこまで致命的ではないのかもしれないですが、スクロールイベントはスクロールをする間アホのように繰り返し呼び出されるのでパフォーマンス的にあまりよろしくないとされています。
そのためlodashなどでイベントの間引き処理をする方法なんてのもあるんですが、Google先生もオススメ!という、ここ数年で話題になっている奴(API)がいます。
Googleも推奨!スクロールイベントの救世主、Intersection Observer(インターセクションオブザーバー)
スクロール連動型イベントの救世主としてここ数年ふつふつと話題になっている(というか既にスタンダードになっている?)のがIntersection Observerです。
インターセクションオブザーバーと読み、直訳すると「交差監視」になります。
こいつは何をしてくれるかというと、文字通り要素と要素が交差しているかどうか(そして交差し終わったかどうか)を監視してくれる粋なヤツです。
つまり要素がビューポートに現れたかどうかなどを検知してくれて、そのタイミングで行う処理も命令できるのです。
なかなか有能ではないか。
ごちゃごちゃ話していても仕方がないので、さっそくサンプルを。
スクロールに応じて時間差で要素が現れるスクロールイベントのサンプルコード
[Javascript]
では見ていきましょう。
大まかな処理の流れは↑のコードにコメントしておきました。
htmlやcssはcodepenのタブからご確認ください。
それではポイントを解説していきます。
要素の位置までスクロールしたら、各要素に時間差でクラスを付与するシンプル構成
スクロールイベントで一番実装することが多いのはこういう実装じゃないでしょうか?(ぼくだけ?)
どうせなら即使えたほうがいいので今回はこんなサンプルにしてみました。
何はともあれターゲット要素を取得
const target = document.querySelectorAll('.target')
const targetArray = Array.prototype.slice.call(target); //IE11でもforEachを正常に回せるように
まずはターゲット要素を取得しましょう。
ポイントでもないんですが、IE11でもforEachが動くように要素たちを明示的に配列としています。
参考
[JS]getElementByIdでは上手くいくのにgetElementsByClassNameでは上手くDOM操作が出来ないとき
オプション設定
const options = { root: null, rootMargin: '0px 0px', threshold: 0 };
今回はオプションはすべて規定値です(大体は規定値=省略でいい気もする)。
とれるオプションはroot / rootMargin / threshold の3つ。
言葉だとちょっと伝わり辛いので↓に図解します。
root
監視する範囲の大枠。
指定されなかった場合、もしくは null の場合はデフォルトでブラウザのビューポートになります。
rootMargin
rootの周りのマージン。単位必須。この枠を基準に要素の交差状況を監視します。
CSSのように”10px 0px 10px 50px”など文字列で指定します。単位必須。%も使用可能だけどその場合はroot指定が必須。
既定はすべて0(サンプルでは明示的に記述してます)。
threshold
ターゲット要素がどのくらいビューポートに侵入してきたかの値。0~1の間で指定する。ターゲットが半分見えた時点で何かするなら値は0.5。
単一の数値もしくは数値の配列で指定する。
これらのオプションを基に監視範囲の詳細が決まります。
Intersection Observerのおっさんを呼ぶ
いきなりおっさん呼ばわりですがIntersection Observerといちいち書くのがだるいのでもうここからはおっさんとします。
さあそれではいよいよおっさんの出番です。↑で決めたオプションとコールバック関数(要素が交差したときに実際に行う処理)を渡しておっさんを呼び出します。
コールバック関数はおっさんが監視要素を発見(交差)した時、おっさんにさせる命令だと考えるとわかりやすいかもしれません。
おっさんを呼び出したうえで、最初に取得した要素の一つ一つに監視マークを付けていきます(forEachで)。
おっさんへの命令(コールバック)を記述
コールバックの引数には交差してきた要素が続々と渡されてきます(entries)。
のでこいつもforEachしてやります。
ここからはコードのポイントを箇条書き的に。
entry.isIntersecting
→ 文字通り「要素が交差してきたら(侵入してきたら)」ということ。
const target = entry.target;
→ 監視要素はforEachの中で「entry.target」で操作可能。
!target.classList.contains('is-active')
→ 一応、is-activeのついていないtarget要素に処理を限定しておきます(まあ無くてもOK)
const delay = i * 100
→ forEachのインデックス番号と任意のミリ秒を乗算することで、後のsetTimeoutにより時間差でクラスを付与することが可能。
observer.unobserve(target);
→ 今回のサンプルでは一度targetにクラスを付与したら処理終了の想定です。
つまりクラス付与後は要素を監視する必要がなくなるので、最後に observer.unobserve(target); で監視を終了させるとパフォーマンス的にもよろしいかと思います。
※ここは実装したい挙動に合わせる必要があるかと思います。
要素が隠れた際(=entry.isIntersectingがfalseになった際)にクラスを削除して、繰り返しアニメーションを発生させる場合には要素監視し続ける必要があります。
なので observer.unobserve(target); は行わないことになるかと思います。
というわけで完成です。
難しそうだったけど意外とシンプルなので初めて使ったときは小躍りして喜びました。
ちなみに交差要素の情報はentry.targetだけではなく色々な情報を取得することが可能です(今回は割愛)。
あとはおっさんの働きを眺めるのみ!
IE11はポリフィルが必要
こんなに有能なおっさんですがやはりIE11パイセンにはおっさんの力が通じません。
なのでおとなしくポリフィルを使いましょう。
npmと、未検証ですがCDNもあるみたいです。
npmはインストールしてimport(かrequire)するだけでOKなお手軽仕様がうれしい。
npm i intersection-observer
<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
とはいえIE11以外はほぼサポート済み
数年前はSafariなどが対象外だったんですが、今やモダンブラウザではほぼ対応済み。
まあGoogleも推奨してるし、これからどんどんスタンダードになっていくんじゃないでしょうか。
交差監視だけじゃない!ほかにもある監視系API(MutationObserver)
というわけでIntersection Observerのおっさんを紹介させてもらいました。
ところで、Observer系のAPIは他にもあって、MutationObserverというおっさんもいるのです(おっさんだらけ)。
こちらはJavascriptで動的に追加した要素を監視して、その要素をさらにごにょごにょできるAPIです。
動的なDOMってたま~に追加でごにょごにょしたくなることがあるんで、頻度は少なそうですがこっちも使い道はありそう。
よかったらそちらも記事にしてるのでどうぞ。
[JS]動的に追加した要素を取得したりごにょごにょできる MutationObserver を使ってみた
ではでは。