超処理が軽いJavaScriptスクロール判定のCSSアニメーション作成方法

スクロール判定の作成方法

作成したサンプルはこちら

一般的に特定の要素までスクロールしたらCSSのactiveクラスを付けてCSSアニメーションを実行する場合、JavaScriptのscrollイベントが使用されるが、scrollイベントを使用すると処理が重くなるという問題がある。

また、特定の要素すべてにactiveクラスを付けてCSSアニメーションを実行する要素がなくなってもscrollイベントを実行し続けているWebサイトが多く存在する。

IntersectionObserverを使用する

scrollイベントではなくIntersectionObserverを使用すると処理が軽くなる。

IntersectionObserverとはターゲットとなる要素を監視するためのAPIで詳細はMDNのWebサイトに書かれているが、内容が少し難しいので最初はターゲットとなる要素までスクロールされたか判定できるAPIだと認識できれば良いです。

IntersectionObserverを使用したコード

まずJavaScriptの前にHTMLとCSSを用意する。

以下のサンプルでは.scrollAnimeの要素までスクロールされた際に.activeが追加された場合はCSSアニメーションが動作するようにした。

<h1>IntersectionObserverによるスクロール位置取得</h1>
<h2>↓ 1000px以上スクロールして確認してみてください。</h2>
<div class="scrollAnime">scrollAnime1</div>
<hr>
<div class="scrollAnime">scrollAnime2</div>
h2, hr {
  margin-bottom: 1000px;
}
.scrollAnime {
  transition: all 1s linear;
  transform: translateX(-20px);
  opacity: 0;
}
.scrollAnime.active {
  transform: translateX(0);
  opacity: 1;
}

JavaScriptは以下の通り。querySelectorAllでCSSアニメーションを動作させる要素を取得する。

すべての要素に.activeが追加された場合はobserver.disconnect()で終了されるため、scrollイベントだけの処理とは違いJavaScriptが動作しつづけることがない。

const targets = [].slice.call(document.querySelectorAll('.scrollAnime'))
const targetsLen = targets.length
if (targetsLen) {
  const observer = new IntersectionObserver(changes => {
    for (let i in changes) {
      if (changes[i].isIntersecting) {
        changes[i].target.classList.add('active')
        const activeLen = document.querySelectorAll('.scrollAnime.active').length
        if (targetsLen === activeLen) {
          observer.disconnect()
        }
      }
    }
  })
  targets.forEach(target => observer.observe(target))
}

ちなみにIntersectionObserverはIE11は使用不可のため、IE11も対象のWebサイトの場合はpolyfill.min.jsを読み込んでください。

polyfill.min.jsを読み込めばIE11でも動作します。

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

IntersectionObserverによるスクロール判定CSSアニメーションサンプル