MENU CLOSE

Intersection Observerを使って
画面内に要素が入ったら
アニメーションさせる

JS
JS

はじめに

画面スクロール時に特定の要素が画面内に入ったら読み込んだり、アニメーションを適用して表示させたりしたい時に使えるAPIのメモ。
こういった実装はこれまでscrollイベントで実装されてきましたが、スクロールするたびにイベントが発生するので負荷がかなり大きく、画面が重くなる原因になりがちでした。そのためrequestAnimationFrameを使ってパフォーマンスを向上させる方法などがググるとたくさん紹介されています。それでもまだ重く感じたり負荷が気になっていたのですが、それを解決する「Intersection Observer API」というものがあることを知ってからはこちらで実装するようになりました。

Intersection Observer APIとは?

直訳すると「交差点監視」という意味ですが、その名の通り「要素同士の交差を判定できる」APIです。指定した要素と要素が交差した時だけイベントが発生するので、これまでのようにスクロールするたびに画面のスクロール位置を取得して目標の要素の位置や高さを取得して条件分岐して・・・というスクロールイベントの闇から解放されます。笑

対応ブラウザ

IEなど一部のブラウザで使えませんが、Edge、Chrome、Firefox、Safari、iOS Safariなどのモダンブラウザの最新バージョンで使えます。もちろんpolyfillがありますので、対応していないブラウザにも対応可能です

Can I use
polyfill

使い方

//オプション指定
const options = {
  //要素の見えている割合が20%を超える度にコールバックを実行
  threshold: [0, 0.2, 0.4, 0.6, 0.8, 1]
}

//交差した時に発生するコールバック
const callback = (entries, observer) => {
  entries.forEach(entry => {
    //交差している領域の割合が20%を超えた場合
    if (entry.intersectionRatio > 0.2) {
      //アニメーションや画像の読み込みなどの処理
    }
  });
}

//IntersectionObserverをインスタンス化
const observer  = new IntersectionObserver(callback, options);

//監視する要素の配列を取得
const observers = [...document.querySelectorAll('.js-event')];

//配列に指定した要素をIntersectionObserverで監視
observers.forEach(el => {
  observer.observe(el);
});

基本的にはこれだけです。コールバックの処理を書く以外にはほとんど何も必要ありません。ただ細かく制御したい場合は以下のポイントを変更すればOKです。

オプション指定

//オプション指定
const options = {
  // ルートとして指定する要素。省略するとデフォルトはviewport
  root: document.querySelector('.root'),

  // 交差する上下左右100px手前で発火させることができる
  rootMargin: "100px",

  //要素の見えている割合が20%を超える度にコールバックを実行
  threshold: [0, 0.2, 0.4, 0.6, 0.8, 1]
}

rootについては基準にしたい要素を指定します。

rootMarginは交差する前にイベントを発生させたい場合に使います。画像の遅延読み込みなんかはこれを使うと画面に入ってくる直前に読み込みできるので便利かもしれませんね。

thresholdはイベントの発生するタイミングを調整できます。例のように配列で指定すると、指定した要素が画面に0%入った時、20%入った時、40
%入った時、60%入った時、80%入った時、100%入った時の計6回、交差している間にコールバックイベントを発生させます。
こちら例として配列を使いましたが、僕は基本的に複数回発生させる処理は不要なので、0.2とか0.5とか配列でなくそのまま数値で指定して1回だけ発生させています。

コールバック

//交差した時に発生するコールバック
const callback = (entries, observer) => {
  entries.forEach(entry => {
    //交差している領域の割合が20%を超えた場合
    if (entry.intersectionRatio > 0.2) {
      //アニメーションや画像の読み込みなどの処理
    }
  });
}

ここではentry.intersectionRatioという部分で、イベント発生した時に交差している割合を取得できるのでそれを使って処理を分岐しています。
他にもイベント発生時に以下のような情報を取得できます。

  • boundingClientRect:イベント発生した要素の座標位置
  • intersectionRect:交差領域の座標位置
  • isIntersecting:イベント発生時に交差しているかどうか
  • isVisible:イベント発生時に要素がすべて見えているかどうか(?)
  • rootBounds:ルート要素の座標情報
  • target:イベント発生した要素
  • time:タイムスタンプ

簡単なデモ

とりあえず簡単なデモを作ってみました。(IE対応はしていません)
DEMO

偶数の番号が書いてある要素が画面内に要素の20%が交差すると背景が黒に変わるアニメーションを付けてみました。

具体的にはコールバック関数に以下を追加しただけのシンプルな実装です。

if (entry.intersectionRatio > 0.2) {
   //クラスを追加
   entry.target.classList.add('is-effect');
}

クラスの付け替えでCSSアニメーションを発生させることができますね。ここではtransitionを使いましたが、もっと複雑な動きならanimationを使った方が良いかもしれません。

さいごに

Intersection Observer APIについてサクッとメモしました。
今までスクロールイベントの負荷で困っていた方や気になっていた方は有効なので使ってみてください。

記事一覧

RELATED

Flatpickr
inoue
inoue
TIPS

Flatpickrで日時入力をカレンダー表示にする

BASE DESIGN THEME
inoue
inoue
TIPS

BASEテーマカスタマイズ【実践編】見出しの文言を変更できるようにする

BASE DESIGN THEME
inoue
inoue
TIPS

BASEテーマカスタマイズ【デザインオプション編】テーマに新しい機能を加える方法

BASE DESIGN THEME
inoue
inoue
TIPS

BASEテーマカスタマイズ【準備編】カスタマイズに必要な前提知識について

BACKGROUND VIDEO
inoue
inoue
TIPS

動画をWebページの背景に埋め込む時のテクニック

Google Apps Script
inoue
inoue
TIPS

【GAS】スプレッドシートからメールを送信する方法

NEW POSTS

Sass @import → @use
inoue
inoue
TRY

【Sass】@importを@useに置き換えてみる《FLOCSS対応》

Stripe Payment Links
inoue
inoue
TRY

コーディング一切不要のStripe Payment Linksで決済機能を試してみる

BASE Partners
inoue
inoue
COLUMN

【BASE Partners】有料テーマの無償提供特典について

BASE Partners
inoue
inoue
COLUMN

BASEオフィシャルパートナーに認定されました

BASE DESIGN THEME Q &A よくある質問
inoue
inoue
COLUMN

【BASEデザインテーマ】よくある質問まとめ

Drawer Menu
inoue
inoue
TIPS

CSSと簡単なJSでできるドロワーメニューの実装方法

ブログ記事一覧
  • HOME
  • TIPS
  • Intersection Observerを使って画面内に要素が入ったらアニメーションさせる