[JS/React] スクロールに合わせてアニメーションさせる

May 26, 2021

programming
article cover

Scroll Listener vs Intersection Observer

スクロール時にアニメーションするには、要素が今どこにあるか常に把握する必要がある。

Event listenerでスクロールアクションを監視する方法が多いが、Intersection Observerというパフォーマンスの優れたAPIがあるので、それを使ってスクロール時のアニメーションを実装する。

How to use

基本的な使い方としては、observerを作り要素を監視させるだけ。

const observer = new IntersectionObserver(callback, options);
const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach((entry) => {
      entry.isIntersecting // return boolean
    })
  }, 
  {
    // option
  }
)

observer.observe(targetElement)

callbackで IntersectionObserverEntry というオブジェクトを受け取り、その中のisIntersectingというプロパティを使うことで、要素がスクリーンの中に入ったかどうか検知することができる。

screen shot

Options

observerを作成する際にオプションを設定することができ、thresholdの値をうまく設定することで、要素がどの程度スクリーンに入ったところで検知するかを調整することができる。

thresholdの値は0から1の間で設定でき、1なら要素とスクリーンの交差(Intersection)が100%になった時にisIntersectingがtrueになり、0なら0%、つまりスクリーンと縁と要素の縁が触れたところでtrueになる。

図にするとこんな感じ。

screen shot

さらにthresholdを配列で設定することにより、細かく要素の位置を検知することができる。

試しにthresholdを[0, 0.01, 0.02 … 0.99, 1]という100段階に設定して、divの背景色を変えてみる。
entry.intersectionRatioを使えば現在要素がどれほどスクリーンに交差しているか取得できる。

const getThresholdArray = () => {
  const threshold = []
  
  for (let i=0; i<=1; i+=0.01) threshold.push(i)
  
  return threshold
}

const observer = new IntersectionObserver(
  (entries) => {
    entries.forEach((entry) => {
      entry.target.style.backgroundColor = `rgba(22, 22, 22, ${entry.intersectionRatio})`
    })
  }, 
  {
    threshold: getThresholdArray()
  }
)

observer.observe(targetElement)

screen shot

スクリーンと要素のIntersectionの具合に合わせて、divの背景色が変わるのを確認できる。

あとは任意のタイミングで任意のアニメーションを付けていけば、スクロールに合わせて自由にアニメーションを実装することができる。

Final code with React


Profile picture

元カメラマン。今はベルリンで働くWEBエンジニア。
スロバキア人の妻とドイツ猫二匹の多国籍家族。