【GSAP】横スクロール内で要素を動かす!containerAnimation の使い方

以前の記事で、GSAPの ScrollTrigger を使った横スクロールアニメーションをご紹介しました。今回はその応用編として、「横スクロールしている最中に、画面内に入ってきた要素をアニメーションさせる方法」を解説します!

関連記事

通常の縦スクロールとは違い、横移動の中で発火させるには containerAnimation というプロパティを使います。これを設定することで、トリガーの判定基準が「上下(top/bottom)」から「左右(left/right)」に切り替わるのが最大のポイントです。 シンプルなデモで仕組みを確認していきましょう!

デモ動作

See the Pen GSAP:横スクロール内でアニメーションを発火させる方法 by mikanbako (@mikanbako) on CodePen.

全画面でのデモ動作は以下のリンクからご確認下さい!(別タブで開かれます)

実装コード紹介

【HTML】

<!-- スクロール用の上の余白 -->
<div class="l-spacer">
  <p>↓ スクロールしてね ↓</p>
</div>

<!-- 横スクロールさせたい親要素 -->
<div class="p-scroll-wrap js-scroll-wrap">
  <!-- 実際に横に動くコンテナ -->
  <div class="p-scroll-container js-scroll-container">
    <section class="p-scroll-panel">
      <p>画面左から20%の位置に来た時発火</p>
      <div class="c-box js-box-1">Box 1</div>
    </section>
    <section class="p-scroll-panel">
      <p>画面の中央に来た時発火</p>
      <div class="c-box js-box-2">Box 2</div>
    </section>
    <section class="p-scroll-panel">
      <p>画面左から80%の位置に来た時発火</p>
      <div class="c-box js-box-3">Box 3</div>
    </section>
  </div>
</div>

<!-- スクロール用の下の余白 -->
<div class="l-spacer">
  <p>↑ 横スクロール終わり ↑</p>
</div>

【CSS】

/* 前後のスクロール余白用 */
.l-spacer {
  height: 100vh;
  display: flex;
  justify-content: center;
  align-items: center;
  font-size: 24px;
  font-weight: bold;
  color: #3e3e3e;
}

/* 横スクロールエリアの親(はみ出した部分を隠す) */
.p-scroll-wrap {
  overflow: hidden;
}

/* パネルを横並びにするコンテナ */
.p-scroll-container {
  display: flex;
  width: max-content;
}

/* 各パネルのデザイン */
.p-scroll-panel {
  width: 100vw;
  height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  font-size: 32px;
  font-weight: bold;
  color: #fff;
}

/* パネルごとの色分け */
.p-scroll-panel:nth-child(1) { background-color: #1bb4d4; }
.p-scroll-panel:nth-child(2) { background-color: #fce621; color: #3e3e3e; }
.p-scroll-panel:nth-child(3) { background-color: #c72c4c; }

/* アニメーションさせる要素 */
.c-box { 
  display: flex;
  align-items: center;
  justify-content: center;
  width: 100px;
  height: 100px;
  margin-top: 20px;
  color: #fff;
  font-size: 20px;
  font-weight: bold;
  border-radius: 12px;
  background-color: #e83e8c;
}

【JavaScript】

// ScrollTriggerプラグインを登録する
gsap.registerPlugin(ScrollTrigger);

// 要素の取得
const wrap = document.querySelector('.js-scroll-wrap');
const container = document.querySelector('.js-scroll-container');

// 💡 1. 横スクロール自体のTweenを作成し、変数に格納する
const scrollTween = gsap.to(container, {
  x: () => -(container.clientWidth - window.innerWidth),
  ease: "none",
  scrollTrigger: {
    trigger: wrap, 
    pin: true,
    scrub: 1,
    start: "top top",
    end: () => "+=" + (container.clientWidth - window.innerWidth), 
    invalidateOnRefresh: true
  }
});

// 💡 2. 各パネルのアニメーションを個別に設定

// 【Box 1】発火:left 20% (要素の左端が、画面左から20%の位置に来た時)
// 動き:下からフワッと浮き上がる
gsap.from('.js-box-1', {
  y: 100,
  autoAlpha: 0,
  duration: 1,
  scrollTrigger: {
    trigger: '.js-box-1',
    containerAnimation: scrollTween, // 横スクロールと連動させる
    start: "left 20%", 
    toggleActions: "play none none reverse"
  }
});

// 【Box 2】発火:center center (要素の中央が、画面の中央に来た時)
// 動き:くるっと回転しながら現れる
gsap.from('.js-box-2', {
  rotation: 360,
  scale: 0,
  duration: 1,
  scrollTrigger: {
    trigger: '.js-box-2',
    containerAnimation: scrollTween, // 横スクロールと連動させる
    start: "center center", 
    toggleActions: "play none none reverse"
  }
});

// 【Box 3】発火:right 80% (要素の右端が、画面左から80%の位置に来た時)
// 動き:横にビヨーンと伸びてから戻る(弾むようなバネの動き)
gsap.from('.js-box-3', {
  scaleX: 0,
  transformOrigin: "left center",
  duration: 1,
  ease: "elastic.out(1, 0.3)", 
  scrollTrigger: {
    trigger: '.js-box-3',
    containerAnimation: scrollTween, // 横スクロールと連動させる
    start: "right 80%", 
    toggleActions: "play none none reverse"
  }
});

コード解説

containerAnimation の指定

// 💡 1. 横スクロール自体のTweenを作成し、変数に格納する
const scrollTween = gsap.to(container, {
  x: () => -(container.clientWidth - window.innerWidth),
  ease: "none",
  scrollTrigger: {
    trigger: wrap, 
    pin: true,
    scrub: 1,
    start: "top top",
    end: () => "+=" + (container.clientWidth - window.innerWidth), 
    invalidateOnRefresh: true
  }
});

// 💡 2. 各パネルのアニメーションを個別に設定
gsap.from('.js-box-1', {
  ...
  scrollTrigger: {
    ...
    containerAnimation: scrollTween, // 横スクロールと連動させる
    ...
  }
});

横スクロールを動かしているアニメーション(今回の場合は scrollTween)を、各要素の ScrollTrigger に紐づけます。これにより、「親の横移動」を基準にして発火タイミングを計算してくれます。

start の方向が変わる

// 【Box 1】発火:left 20% (要素の左端が、画面左から20%の位置に来た時)
gsap.from('.js-box-1', {
  ...
  scrollTrigger: {
    ...
    containerAnimation: scrollTween,
    start: "left 20%", 
    ...
  }
});

通常の縦スクロールでは start: "top center"(要素の上が画面中央にきたら)のように指定しますが、横移動の場合は start: "left center"(要素の左端が画面中央にきたら) のように、left や right を使ってX方向の判定を行います!

各トリガー(start)の違いに注目!

start: "left 20%"(Box 1)
要素の「左端(left)」が画面の「左から20%の位置」に来た時に動きます。遅めの発火アニメーションです。

start: "center center"(Box 2)
要素の「中央」が画面の「中央」に来た時に動きます。画面のど真ん中でアニメーションさせたい時に使います。

start: "right 80%"(Box 3)
要素の「右端(right)」が画面の「左から80%の位置」に来た時に動きます。早くアニメーションを見せたい時に使います!

補足:公式ドキュメント

より詳しい仕様や最新の対応状況については、以下の公式ドキュメントをご参照ください。

・GSAP: ScrollTrigger
・GSAP: ScrollTrigger/containerAnimation

まとめ

今回はScrollTrigger を使った横スクロールアニメーションの応用編として、「横スクロールしている最中に、画面内に入ってきた要素をアニメーションさせる方法」を解説しました!

この横スクロール+出現アニメーションの組み合わせは頻繁に使われます。応用が効くテクニックなので、ぜひマスターしてみてください!

Prev
Next