スクロールに合わせたアニメーション、昨今はクライアントさんがぐりぐり動かしたいっ、というケースが増え必須技術になっていますが、レスポンシブで行う場合、スクロール量が変化する為それなりに面倒です。これまで様々なプラグインもありました。「Intersection Observer API」を使うと、効率的にソースを書くことが出来る!!便利だ。ということで、使い回しがしやすいパタンを作っておくことにしました。

Intersection Observer API

Intersection Observer API 「交差監視 API」。要素と、祖先要素または最上位のビューポートとの交差を非同期で監視します。スクロール量計算ではなく、交差したタイミングを取りますので、可視領域に入った時にアニメーションを発動することが出来ます。可視領域から外れた場合の動作指定ももちろん可能です。

交差したら、class名を付与する

アニメーション自体はCSSで作成し、可視領域に入ったら要素にclassを付与、アニメーションが発火する、という使い勝手の良さそうなシチュエーションで試してみました。
※複数個数にアニメーションをつけるために、少し時間をずらしてアニメーションするようにしています。

<script>
const doObserve = (element) => {
  const targets = document.querySelectorAll(element);
  const options = {
    root: null,
    rootMargin: "10% 0px", 
    threshold: [0.2, 1.0], //20%から100%
  };
  const observer = new IntersectionObserver((items) => {
    items.forEach((item, index) => {
      if (item.isIntersecting) {
        setTimeout(() => {
          item.target.classList.add('is-visible')
        }, index * 150)
      } else {
        item.target.classList.remove('is-visible')
      }
    })
  }, options)
  Array.from(targets).forEach((target) => {
    observer.observe(target)
  })
};
doObserve('.hoverGrid'); //監視対象の指定
</script>

後は該当要素に「is-visibleクラス」が付与された場合に、CSSアニメーションを適用するようにCSSを用意します。追加で別のアニメーションを作る場合は「doObserve2」のように名称を変更すればOKです。

Options

IntersectionObserverにはオプションがあります。オプションの指定は、コンストラクタの第二引数にオブジェクトを渡します。

名称デフォルト
rootルート(交差判定のベース)となる要素。rootを指定すると、viewport以外との交差判定ができます。viewport
rootMarginroot要素からの距離です。「マイナス値」を設定するとルート要素の手前で交差を検知します。単位はpxまたは%で指定し、単位をつけて指定します。0px 0px 0px 0px
thresholdコールバックが呼ばれるタイミング。交差を検知する閾値で、0~1の値を設定することができます。デフォルト0の場合は交差領域が0、つまり重なり始めと重なり終わりに検知されます。0

thresholdが少し分かりにくいかな。領域に入った、出た、だけではその間でアニメーションを呼び出すことはできませんが、以下のようにthresholdの引数を設定すると、交差領域が 20% 変化する毎にコールバックを呼ぶことができるようになります。より複雑なインタラクションアニメーションが設定出来るということですね。

{ threshold: [0, 0.2, 0.4, 0.6, 0.8, 1.0] }


IE11への対策

Intesection Observer APIはIE11では対応していませんので、ポリフィルを利用します。<head>内に追加すればOKです。
https://github.com/w3c/IntersectionObserver/tree/master/polyfill

<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.js?features=IntersectionObserver"></script>