2019.02.02

Intersection Observerで要素が画面内に入ったときにアニメーションや自動スクロールをスタートする


この記事では、Intersection Observer とその利用例を紹介します。

  • ある要素が画面上に見えたとき、アニメーションを開始する
  • 同様にある要素が画面上に見えたとき、スライダーを自動で動かす

Intersection Observer

Intersection Observer とは

Intersection Observer は JavaScript の機能の一つです。直訳すると「交差の監視役」でしょうか。「交差」とは聞きなれない言葉ですが、【基準の要素】と【監視される要素】の重なり具合を意味します。

例えばブラウザ画面全体を基準としてある要素を監視したとき、監視対象が30%見えていたら、基準であるブラウザ画面と監視対象が30%重なっている(=交差している)と考えます。

ある基準に対して監視対象が見えている割合と言ってしまっても良いでしょう。

使い方

IntersectionObserver オブジェクトは以下のように生成します。

const observer = new IntersectionObserver(callback, options);
  • 第一引数:交差割合が変わったときに実行されるコールバック関数
  • 第二引数:以下のオプション 👇
const options = {
  root: null,
  rootMargin: 0,
  threshold: [0.25, 0.5]
}

オプションに指定できるのは以下の3つの項目です。

  • root:基準の要素。デフォルトはブラウザ画面。
  • rootMargin:交差を計算する際は、実際は基準要素の領域にここで指定した余白値を足した領域が計算基準となる。つまり例えばここに正の値を指定すれば、実際に見える前に交差していると判定させることができる。デフォルトはゼロ。
  • threshold:コールバックを実行する交差の閾値リスト。交差の割合が閾値を上回るか下回ったときのみコールバック関数が実行される。上の例でいうと、見えている割合が25%および50%を上回るか下回ったときにコールバックが実行される。デフォルトはゼロ。

そして observe メソッドで監視を開始します。

const target = document.querySelector('#something')
observer.observe(target)

監視対象の要素を observe メソッドの引数に指定します。

最後に、コールバックはどのような関数なのでしょうか。

const callback = (entries, observer) => {
  entries.forEach(entry => {
    // ...
  })
}
  • entries:交差オブジェクトの配列。配列になっているのは、先ほどの observe メソッドを複数回呼び出せば複数の要素を監視できるため。つまり監視対象ごとの交差オブジェクトが入った配列。このオブジェクトから交差の割合などの情報を引き出せる。
  • observer:コールバックを渡した IntersectionObserver オブジェクト。

メリット

Intersection Observer を使用するメリットは、閾値の前後でしかコールバックが呼ばれないことでしょう。scroll イベントでも画面上に見えているかどうかを判定する処理は実装できそうですが、その場合はスクロールするたびに判定コードが実行されてしまいます。Intersection Observer を使えばあらかじめ定めた閾値により必要なときにしか判定コードが呼ばれないため、よりブラウザへの負担が少ない実装が可能になります。

ではこの Intersection Observer の活用例を見ていきましょう。

アニメーション

まずは要素が見えたときにアニメーションをスタートする例です。
赤い背景のセクションが見えたときに文字がアニメーションしながら表示されます。

See the Pen IntersectionObserver Demo by Masahiro Harada (@MasahiroHarada) on CodePen.

コードの全容は上 👆 の CodePen を見ていただくとして、ポイントのみ説明します。

まず今回は20%と100%の閾値を設定しました。
そのほかのオプションはデフォルトのままなので省略します。

const option = {
  // 20%と100%の閾値
  threshold: [0.2, 1.0]
}

コールバックは以下の通りです。

const callback = (entries, observer) => {
  entries.forEach(entry => {
    if (entry.intersectionRatio === 1) {
      // 100%見えなくなったとき
      entry.target.classList.add('active')
    } else if (! entry.isIntersecting) {
      // 見えている領域が20%を下回ったとき
      entry.target.classList.remove('active')
    }
  })
}

active クラスに CSS アニメーションを定義しているため、100%見えたときにクラスをつけて、20%以上見えなくなったときにクラスを外します(もう一度見たときに再度アニメーションが動くように)。

コールバックの内部では交差オブジェクトが持つプロパティのうち、intersectionRatioisIntersecting を参照しています。

intersectionRatio は交差の割合です。コールバックは閾値を上回るか下回ったタイミングで呼ばれるわけですが、そのときの intersectionRatio の値は 0.22546914219856262 のような中途半端な値なので注意してください。1未満の閾値について判定する場合はイコールではなく、閾値以上(または未満)かどうかで判定するのがよいでしょう。

isIntersecting は交差が閾値を超えているかどうかを表す真偽値です。複数の閾値が設定されていた場合は、すべての閾値を満たさない場合に false となります。

自動スクロール

次にスクロール領域が見えたときに自動スクロールをスタートさせる例です。
スクロール機能の実現には Swiper を使用しています。

「すべて見えるとき」と「すべて見えないとき」を検知したいので、0と1を閾値にします。

{ threshold: [0, 1.0] }

コールバックはアニメーションの例と同じパターンですね。

function intersectionCallback(entries) {
  entries.forEach(entry => {
    if (entry.intersectionRatio >= 1) {
      // 対象の要素がすべて見えたとき
      swiper.autoplay.start()
    } else if (entry.intersectionRatio === 0) {
      // 対象の要素がすべて見えなくなったとき
      swiper.slideToLoop(0)
      swiper.autoplay.stop()
    }
  });
}

今回はセクション全体ではなくスクロール領域を監視対象としています。

const target = document.querySelector(".swiper-container")
observer.observe(target)

ポリフィル

残念ながら Intersection Observer は IE と現時点の Safari では実装されていません。

Can I Use

参考:http://caniuse.com/#feat=intersectionobserver

ポリフィルを読み込むことで未実装のブラウザでも Intersection Observer を利用できます。

<script src="https://polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>

以上、Intersection Observer とその利用例を紹介しました。