🥑

Lottieアニメーションをスクロール量に応じて制御する

2024/01/30に公開

GSAPのScrollTriggerでLottieアニメをスクロール量に応じて再生します。

DEMO

https://lottie-vite.vercel.app/
lottieを描画する部分をposition:fixdedで固定しています。

クリックするとtopに戻ります。

Lottieとは

Lottie(ロッティー)は、Airbnbが開発したライブラリで、ウェブやモバイルアプリケーションでベクトルアニメーションを再生するためのツールです。

https://lottiefiles.com/jp/

Lottieのメリット

  1. ベクトルアニメーションのサポート: Lottieはベクトル形式のアニメーションをサポートしており、異なる画面サイズや解像度に対しても高品質なアニメーションを提供します。
  2. プラットフォームの対応: LottieはWeb(JavaScript)、iOS(Swift/Objective-C)、Android(Java/Kotlin)の各プラットフォームで利用可能です。
  3. After Effectsとの統合: LottieはAdobe After Effectsと統合でき、デザイナーはAfter Effectsでアニメーションを制作し、そのデータをLottieが解釈できるJSON形式にエクスポートすることができます。
  4. 軽量で高性能: LottieはコンパクトなJSON形式を使用しているため、アニメーションデータが比較的小さく、ネットワーク通信やアプリケーションのパフォーマンスにおいても効率的です。
  5. 多彩なアニメーション効果: イージングやトリガーアクション、ループ、逆再生など、さまざまなアニメーション効果をサポートしています。

Lottieのデメリット

  1. 単色のsvgでないと無理 : グラデーションでの塗りつぶしは不向きな様です
  2. アクセシビリティへの対応が必要:altタグやスクリーンリーダーへの対応が別途必要な様です

いちばん簡単な再生方法

CDNを読み込みlottie-playerタグを貼ることで簡単に再生できます。

以下のリンクでパラメータをいじりつつコードを作成できます。

https://lottiefiles.com/jp/web-player

Lottieファイルの作成

LottieファイルはAfter Effects, FIGMA, Lottie Creatorなどで作成することができます。

今回はプラットフォームに公開されているファイルを使用するため、作成方法については割愛します。

以下のリンクが参考になるかと思います。

https://ics.media/entry/230913/
https://ics.media/entry/230928/
https://creator.lottiefiles.com/?fileId=9a2fefea-5937-45cc-8b56-31331e7f1419

ScrollTriggerでLottieを制御する

本記事の肝です。まずは完成コードを御覧ください。

viteを使用しています。

JSONファイルはpublicフォルダ直下から呼び出しています。

完成コード

ディレクトリ構成
\lottie-vite\
│  .gitignore
│  index.html
│  main.js
│  package-lock.json
│  package.json
│  style.css
├─node_modules           
└─public
        sample_01.json
index.html
<!doctype html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ScrollTriggerSample</title>
  <body class="home">
    <h1>ScrollTriggerSample</h1>
    <a href="#">
      <div id="animationWindow"></div>
    </a>
    <script type="module" src="/main.js"></script>
  </body>
</html>
style.css
body.home {
  height: 300vh;
  width: 100%;
  margin: 0;
  padding: 0;
}
h1 {
  font-size: clamp(16px,2vw,32px);
  position: fixed;
  top: 20%;
  left: 20%;
}
#animationWindow {
  max-width: 60%;
  aspect-ratio: 800 / 400;
  height: auto;
  position: fixed;
  bottom: 20%;
  left: 20%;
  border: solid 1px black;
}
main.js
import './style.css'
import gsap from "gsap";
import lottie from 'lottie-web';
import ScrollTrigger from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);

const ScrollLottie = (obj) => {
  let anim = lottie.loadAnimation({
      container: document.querySelector(obj.target),
      renderer: "svg",
      loop: false,
      autoplay: false,
      path: obj.path,
  });

  let timeObj = { currentFrame: 0 };
  let endString =
      obj.speed === "slow"
          ? "+=2000"
          : obj.speed === "medium"
            ? "+=1000"
            : obj.speed === undefined
              ? "+=1250"
              : "+=500";
  ScrollTrigger.create({
      trigger: obj.target,
      scrub: true,
      markers: true,
      // pin: true,
      start: "top top",
      end: endString,
      onUpdate: (self) => {
          if (obj.duration) {
              gsap.to(timeObj, {
                  duration: obj.duration,
                  currentFrame: Math.floor(
                      self.progress * (anim.totalFrames - 1),
                  ),
                  onUpdate: () => {
                      anim.goToAndStop(timeObj.currentFrame, true);
                  },
                  ease: "expo",
              });
          } else {
              anim.goToAndStop(
                  self.progress * (anim.totalFrames - 1),
                  true,
              );
          }
      },
  });
};

ScrollLottie({
  target: "#animationWindow",
  path: "./sample_01.json",
  duration: 1,
  speed: "slow",
});

依存関係のインストール

npm install lottie-web

npm install gsap

import lottie from 'lottie-web';
import gsap from "gsap";
import ScrollTrigger from "gsap/ScrollTrigger";
gsap.registerPlugin(ScrollTrigger);

lottie-web, gsap, ScrollTriggerをインストールします。

CDNでも可能ですが割愛させていただきます。

Lottieアニメーションのロード

let anim = lottie.loadAnimation({
  container: document.querySelector(obj.target),
  renderer: 'svg',
  loop: false,
  autoplay: false,
  path: obj.path
});

lottie.loadAnimationメソッドを使用して、指定されたobj.target内にLottieアニメーションをロードします。rendererはSVGを使用し、loopはアニメーションのループを無効に、autoplayは自動再生を無効に、pathはアニメーションのJSONファイルのパスを指定します。

ScrollTriggerの設定

ScrollTrigger.create({
      trigger: obj.target,
      scrub: true,
      markers: true,
      start: "top top",
      end: endString,
  onUpdate: self => {
   // ...
  }
});

ScrollTriggerを作成して、スクロールに応じてアニメーションを制御するための設定を行います。scrubはスクロールに応じてアニメーションを滑らかに制御し、startとendはアニメーションのトリガーの範囲を指定します。onUpdateコールバックでは、スクロールの進捗に応じてアニメーションの進行を更新します。

アニメーションの進捗に応じた処理

onUpdate: self => {
   if(obj.duration) {
    gsap.to(timeObj, {
     duration: obj.duration,
     currentFrame:(Math.floor(self.progress *  (anim.totalFrames - 1))),
     onUpdate: () => {
      anim.goToAndStop(timeObj.currentFrame, true)
     },
     ease: 'expo'
    })
   } else {
     anim.goToAndStop(self.progress *  (anim.totalFrames - 1), true)
   }
}

onUpdateコールバック内では、スクロールの進捗に応じてアニメーションの進行を制御します。もしobj.durationが指定されていれば、GSAPのtoメソッドを使用して指定された時間でアニメーションを進めます。それ以外の場合は、スクロールの進捗に基づいてアニメーションを進行させます。

プロパティの設定

ScrollLottie({
  target: "#animationWindow",
  path: "./sample_01.json",
  duration: 1,
  speed: "slow",
});

プロパティを設定してScrollLottieを呼び出します。

参考資料

https://gsap.com/docs/v3/HelperFunctions/helpers/LottieScrollTrigger
https://github.com/chrisgannon/ScrollLottie

GSAP公式にScrollTriggerでの制御について掲載されているのですが、そのinspire元を今回は参考にさせていただきました。

Appendix

https://lottiefiles.com/jp/interactivity
今回はGSAPで制御しましたが、lottieをインタラクティブに制御する手段を公式で用意してくれています。

Discussion