この記事ではIntersectionObserverの使い方を説明します。IntersectionObserverを使うと簡単にスクロールの非同期処理を実装することができます。
各ブラウザの対応状況
こちらは各ブラウザの対応状況です。IEはさておき、EdgeとSafariが一世代前のバージョンで対応していません。本格的に利用する場合はPolyfill*1を使用してください。
従来の実装とIntersectionObserverのメリット
これまでのスクロール処理は以下のような処理をつらつら書く必要がありました。
1 2 3 4 5 6 7 8 | window.addEventListener('scroll', function () { // スクロール位置の取得して、スクロール位置でトリガーしたい要素の高さ取得して、 // 画面に要素が入ってきたとき、要素が出ていったときを判定、 // 要素がすでに実行されているとき、されていないときを判定、(例えばアニメーションなど) // 色々加味してすべて満たしていれば実行!!! // 一度だけ実行したい場合はフラグを切り替え! // 以下... }, {passive: true}); |
従来の処理では様々な条件をプログラマーが考慮して実装する部分が多く、記述が冗長な面がありました。
しかしIntersectionObserverを用いると簡単にスクロール処理を記述することができます。更にIntersectionObserverは非同期で処理を実行するため、ユーザーのスクロールを邪魔することがなく、スムーズなスクロールを実現することができます。
IntersectionObserverの使い方
#target
要素が画面内に入ってきた際に発火するIntersectionObserverの書き方は次の様になります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | var target = document.querySelector('#target'); // 対象のエレメント // optionは省略可能、初期値は以下のようになります。 var option = { root: null, rootMargin: "0px", threshold: [0] }; // 交差した際の処理を記載 var callback = function (entries, observer) { entries.forEach(function (entry) { // 交差している場合はtrue if (entry.isIntersecting) { // 処理実行 // 処理完了後、監視を止めたい場合 observer.unobserve(entry.target); } }); }; var observer = new IntersectionObserver(callback, option); // callback, optionを設定 // Polyfillを使っている場合コメントアウトを外す // observer.POLL_INTERVAL = 100; observer.observe(target); // 監視を開始 |
オプションのパラメータ説明
オプションの値は省略可能です。必要に応じて設定しましょう。
1 2 3 4 5 | var option = { root: document.querySelector("#ancestor"), // 指定しない場合はviewportがrootになる rootMargin: "0px", // 必ずpxまたは%をつける threshold: [0, 0.5, 1.0] // 指定しない場合は[0] }; |
使用上の注意点
- rootMarginを使用する場合は必ずpxか%を使用する。また、%を使用する場合は必ずrootを指定しましょう。*1
- 一度作成したオブジェクトのプロパティー(root, rootMargin, threadhold)は変更できないので、違う値にしたい場合は新しくオブザーバーを作成しましょう。
- rootはトリガーしたい要素の祖先でなければならないため、rootはtargetを必ず囲んでいる要素を指定しましょう。
- IEと一部ブラウザでは対応していないので、polyfill(対応していないブラウザで正常に動くようにするスクリプト)をあわせて使用しましょう。
*1 指定していない場合は以下のエラーがコンソールに表示されます。
Uncaught DOMException: Failed to construct ‘IntersectionObserver’: rootMargin must be specified in pixels or percent.
Intersection Observerを使った実装例
使用例1. Viewportと要素の交差を判定
こちらのデモはすべてのタイルにobserverをセットし、Viewportに入ってきたタイミングで色を変更しています。
ソースを見る
<meta name="viewport"
の様に記述されるmetaタグもViewportと呼ばれます。2種類の意味で使われる事があるので注意しましょう。使用例2. thresholdの使用例
こちらはthreshold
を使ったデモです。
thresholdに0~1の数字の配列を設定すると、そのしきい値で処理が実行されます。また、指定しない場合は[0]と同等です。
下のデモではthreshold: [0, 0.25, 0.5, 0.75, 1.0]
を設定しています。
使用例3 rootがViewport以外の場合の交差を判定
このデモではrootオプションにサイドバーを設定し、サイドバーのコンテナとサイドバー内の要素を交差を判定しています。
この様にrootに特定の要素を設定し、その要素との交差の判定も行うことができます。
*rootに設定する要素は、交差対象の要素の先祖要素である必要があります。
ソースを見る
コールバック時に参照できる情報
こちらはコールバック時に参照できる関数の一覧です。
1 2 3 4 5 6 7 8 9 10 11 12 13 | var callback = function(entries, observer) { entries.forEach(entry => { // entryのプロパティーから以下の値が参照できます。 // また、この値は読み込み専用なので、高速に参照できます。 // entry.boundingClientRect // targetの位置、大きさ // entry.intersectionRatio // 交差割合(0 ~ 1) // entry.intersectionRect // 交差しているtargetの位置、大きさ // entry.isIntersecting // 交差しているか // entry.rootBounds // rootの位置、大きさ // entry.target // targetセレクタ // entry.time // targetが交差した瞬間の時間 }); }; |
IntersectionObserverに向いていない処理
現状使用していてIntersectionObserverが向いていないと感じるのは『2つの要素が交わるという条件を画面上で作りづらい場合』です。
例えば、基準となるtarget要素がない場所でスクロール処理を行いたい場合はwindow.addEventListener('scroll',()=>{});
を使用したほうが制御が簡単になります。
(IntersectionObserverでできなくもないですが、この場合はscrollリスナーを使用する方が自然なのではないかと思います。まあ、考えて見れば当たり前ですね。)
実際、次の記事で上げているスクロール処理は特定のtarget要素がないため、scrollリスナーを使用しています。
まとめ
Intersection Observerを使用するとスクロール処理が簡単に記述できます。また、Polyfillを入れれば旧ブラウザの対応も問題ないです。
ユーザーのスクロール処理を邪魔することもなく、直感的にスクロール処理が記載できるIntersection Observer!おすすめです!是非使ってみてください。