スクロールのプログレスバーをキャラクターアニメーションで表現したスニペット

⚠この記事が公開されたのは 2023年5月8日で、内容が古く、間違っている可能性があります。

長いぺージをスクロールした際に、「今どれくらい読んだか」という状況を示すプログレスバーを設置することがあります。
このプログレスバーをキャラクターが走るアニメーションで表現してみました。

デモ

codepenの上でカーソルをホバーしてマウススクロールするとマリオが左右に走ります。

必須ライブラリ

  • gsap.min.js (アニメーション用のライブラリ)
  • scrollTrigger.min.js (スクロールイベントでアニメーションさせるライブラリ)

インストール

アニメーション用の画像


アニメーションはCSSスプライトを応用しますので以下のような画像を作成してください。

  • アニメーションさせるフレームの数だけ左から右に画像(コマ)を並べて配置
  • 1コマの大きさは任意ですが今回の例では横90px x 縦96pxで作成(2コマの場合は画像ファイルは180px x 96pxとなる)
  • アニメーションをループさせる場合は最初と最後がつながるようにデザインする
  • ファイル形式はjpgやpngなどなんでもいいがコマ数が多くなるとファイルサイズが大きくなるので背景透過の有無や画質などを考慮して最適なファイル形式を検討する

HTML

CDNを利用する場合はscriptタグをHTMLの任意の場所に記述

bodyの閉じタグ直前の例

<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/gsap.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.11.5/ScrollTrigger.min.js"></script>
<script src="script.js"></script>

スクロールする要素(例:bodyまたはmain, artcleなど)を.scroll-areaとしたHTMLの例

<div class="scroll-area">
  <div class="progress-bar">
    <div class="mario-wrapper">
      <span class="mario"></span>
    </div>
  </div>
</div>

CSS

.scroll-area { //スクロールを検知するエリア
  position: relative;
  height: 400vh;
  overflow-x: hidden;
}
.progress-bar { //画面の80%幅で中央に固定
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 80vw; 
  border-bottom: 5px solid black;
}
.mario-wrapper { //キャラクターを左右に反転させるラッパー要素
  height: 96px;
}
.mario {
  display: block;
  position: absolute;
  width: 90px;
  height: 96px;
  background-image: url("https://blog.bytedesign.net/wp-content/uploads/2023/05/codepen_running.png");
  background-repeat: repeat-x;
  content: "";
}

script.js

const progressBar = document.querySelector(".progress-bar");
const progressBarWidth = progressBar.offsetWidth;
const mario = document.querySelector(".mario");
const xLength = progressBarWidth - mario.offsetWidth;
const frame_count = 180;
const offset_value = 90;

gsap.set(".mario-wrapper", {
  x: 0,
});

gsap.to(".mario-wrapper", {
  x: xLength,
  scrollTrigger: {
    trigger: "scroll-area",
    start: "top top",
    end: "bottom bottom",
    scrub: true,
    onUpdate: ({ direction }) => {
      mario.style.transform = `scale(${direction === 1 ? 1 : -1}, 1)`;
    },
    onLeaveBack: () => {
      mario.classList.remove("scrolling-up");
    },
  },
});

gsap.set(".mario", {
  backgroundPositionX: 0,
});

gsap.to(".mario", {
  backgroundPositionX: `${-offset_value * frame_count}px`,
  ease: `steps(${frame_count})`,
  scrollTrigger: {
    trigger: "scroll-area",
    start: "top top",
    end: "bottom bottom",
    scrub: true,
  },
});

使い方

以上でスクロールした際にマリオが左右に走ると思います。
あとは.progress-bar要素をposition: fixedで画面上部や下部に固定するとUXが向上すると思います。