GSAP ScrollTrigger 入門 - 基本編:スクロールアニメーションの実装

GSAP ScrollTrigger 入門 - 基本編:スクロールアニメーションの実装

作成日:
更新日:

スクロールに連動したアニメーションは、現代のWebサイトにおいて欠かせない要素となっています。ランディングページ、ポートフォリオ、ストーリーテリング型のサイトなど、ユーザーの注目を集め、エンゲージメントを高めるために広く活用されています。

GSAP(GreenSock Animation Platform)ScrollTrigger プラグインは、そのようなスクロールアニメーションを驚くほど簡単に実装できるツールです。CSSのIntersection Observer APIや複雑なスクロール計算を自分で書く必要がなく、宣言的なコードでプロフェッショナルなスクロール演出を実現できます。

この記事では、ScrollTriggerの基本的な使い方をデモとコード例を交えて解説します。初めてScrollTriggerを使う方でも、この記事を読み終える頃には基本的なスクロールアニメーションを実装できるようになります。


GSAPとScrollTriggerとは

GSAP

GSAPは、Web上で最も使われているJavaScriptアニメーションライブラリの一つです。2008年にFlash向けとして誕生し、現在はJavaScript版として世界中で1000万以上のサイトで使用されています。

GSAPが選ばれる理由:

特徴説明
高いパフォーマンス60fpsを維持する最適化されたアニメーションエンジン
ブラウザ間の一貫した動作IE11からモダンブラウザまで同じ動作を保証
直感的なAPIgsap.to(), gsap.from(), gsap.timeline() などシンプルな構文
豊富なプラグインScrollTrigger、Draggable、MorphSVGなど20以上のプラグイン
活発なコミュニティ公式フォーラム、豊富なドキュメント、StackOverflowでのサポート

ScrollTrigger

ScrollTriggerは、GSAPのプラグインで、スクロール位置に基づいてアニメーションを制御できます。2020年にリリースされて以来、スクロールアニメーションの実装方法を一変させました。

ScrollTriggerでできること:

機能説明使用例
トリガー要素が画面に入ったらアニメーション開始フェードイン、スライドイン
scrubスクロール位置にアニメーションを同期プログレスバー、回転効果
pin要素をビューポートに固定ストーリーテリング、製品紹介
コールバック特定のタイミングで関数を実行分析、状態管理
snap特定の位置に吸い付くようにスクロールセクション間移動

これらの機能を組み合わせることで、Apple、Nike、Airbnbのようなインタラクティブなスクロール体験を構築できます。

セットアップ

GSAPとScrollTriggerのセットアップは非常に簡単です。CDNを使用する方法と、npm/yarnを使用する方法の2つがあります。


CDNを使う場合

HTMLファイルに直接スクリプトタグを追加する最もシンプルな方法です。プロトタイピングや小規模なプロジェクトに適しています。

HTML
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12/dist/gsap.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/gsap@3.12/dist/ScrollTrigger.min.js"></script>

注意: GSAPのコアライブラリ(gsap.min.js)を先に読み込む必要があります。順序を間違えるとエラーになります。


npm/yarnを使う場合

React、Vue、Next.jsなどのモダンなフレームワークを使用している場合は、パッケージマネージャーでインストールします。

Shell
npm install gsap

インストール後、以下のようにインポートして使用します。重要なのはgsap.registerPlugin()でScrollTriggerを登録することです。これを忘れるとScrollTriggerが動作しません。

JavaScript
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
 
// プラグインを登録(必須!)
gsap.registerPlugin(ScrollTrigger);

ポイント: registerPlugin()はアプリケーション全体で一度だけ呼び出せば十分です。Reactの場合は、ルートコンポーネントやレイアウトコンポーネントで呼び出すのがおすすめです。

基本的なスクロールアニメーション

最もシンプルな例として、要素が画面に入ったらアニメーションを開始する実装を見てみましょう。ScrollTriggerの魅力は、わずか数行のコードで複雑なスクロール演出を実現できることです。


最小構成

ScrollTriggerの最小構成は驚くほどシンプルです。通常のGSAPアニメーションにscrollTriggerプロパティを追加するだけです。

JavaScript
gsap.to('.box', {
  scrollTrigger: '.box', // この要素がビューポートに入ったらトリガー
  x: 500
});

たったこれだけで、.box 要素が画面に入ったら右に500px移動するアニメーションが実装できます。scrollTriggerに文字列(セレクタ)を渡すと、その要素がビューポートに入ったときにアニメーションが開始されます。


より詳細な設定

実際のプロジェクトでは、アニメーションのタイミングや動作をより細かく制御したい場合が多いでしょう。scrollTriggerにオブジェクトを渡すことで、詳細な設定が可能になります。

JavaScript
gsap.to('.box', {
  x: 200,
  duration: 1,
  scrollTrigger: {
    trigger: '.box',        // トリガーとなる要素
    start: 'top 80%',       // 要素のtopがビューポートの80%位置に来たら開始
    end: 'top 20%',         // 要素のtopがビューポートの20%位置に来たら終了
    toggleActions: 'play none none reverse',
    markers: true,          // デバッグ用マーカーを表示
  },
});

各プロパティの説明:

プロパティ説明
triggerアニメーションのトリガーとなる要素。スクロール位置の基準になる
startアニメーションが開始される位置
endアニメーションが終了する位置
toggleActions4つのタイミング(enter, leave, enterBack, leaveBack)での動作を指定
markersデバッグ用のマーカーを表示(開発時に便利)

デモ:基本的なアニメーション

スクロールして、各要素のアニメーションを確認してください。移動、回転、フェードインなど、基本的なアニメーションパターンを確認できます。

Loading...

このデモでは3種類のアニメーションを実装しています。それぞれのボックスが画面に入ると、設定されたアニメーションが再生されます。

start と end の指定方法

startend は、アニメーションの開始位置と終了位置を指定する最も重要なプロパティです。この設定を理解すれば、思い通りのタイミングでアニメーションを制御できます。


基本構文

startendは、2つの位置を半角スペースで区切って指定します。

start: "トリガー要素の位置 ビューポートの位置"
end: "トリガー要素の位置 ビューポートの位置"

例えば、start: "top center" は「トリガー要素のtopビューポートのcenterに到達したとき」という意味になります。


使用できる値

ScrollTriggerでは、複数の方法で位置を指定できます。状況に応じて使い分けましょう。

説明
top要素/ビューポートの上端start: 'top top'
center要素/ビューポートの中央start: 'center center'
bottom要素/ビューポートの下端start: 'bottom bottom'
80%パーセント指定(0%=top、100%=bottom)start: 'top 80%'
+=100相対値(ピクセル単位)end: '+=500'

よくある設定パターン

実際のプロジェクトでよく使用されるパターンをいくつか紹介します。

JavaScript
// 要素のtopがビューポートの中央に来たら開始
start: 'top center'
 
// 要素のbottomがビューポートの上端に来たら開始
start: 'bottom top'
 
// 要素のtopがビューポートの80%位置に来たら開始
start: 'top 80%'
 
// 開始位置から500px スクロールしたら終了
end: '+=500'

💡 開発のヒント: markers: true を設定すると、start/endの位置が視覚的に表示されます。位置の調整時に非常に便利です。

toggleActions

toggleActions は、スクロールの方向と位置に応じてアニメーションの動作を制御する強力なプロパティです。ユーザーがスクロールを上下どちらに動かしても、適切なアニメーションの振る舞いを設定できます。


構文

toggleActionsは、4つのタイミングでのアクションを半角スペースで区切って指定します。

toggleActions: "onEnter onLeave onEnterBack onLeaveBack"

それぞれのタイミングの意味:

イベント発生タイミング説明
onEnter開始位置を下方向にスクロールで通過ユーザーが要素に近づいてきたとき
onLeave終了位置を下方向にスクロールで通過ユーザーが要素を通り過ぎたとき
onEnterBack終了位置を上方向にスクロールで通過ユーザーが戻ってきたとき
onLeaveBack開始位置を上方向にスクロールで通過ユーザーが上に戻って離れたとき

使用できるアクション

各タイミングで指定できるアクションは以下の通りです。

アクション説明使いどころ
playアニメーションを再生基本的な開始
pauseアニメーションを一時停止現在の位置で停止
resume一時停止したアニメーションを再開pauseの後に使用
resetアニメーションを最初に戻す状態をリセット
restart最初から再生毎回最初から見せたい場合
complete最後まで即座に進めるすぐに完了状態にしたい場合
reverse逆再生戻ったときにアニメーションを巻き戻す
none何もしない特定のタイミングを無視

よく使うパターン

JavaScript
// 入ったら再生、戻ったら逆再生(最もよく使う)
toggleActions: 'play none none reverse'
 
// 入るたびに最初から再生
toggleActions: 'restart none none none'
 
// 出たらリセット、戻ったら再生(毎回フレッシュな状態で見せる)
toggleActions: 'play reset play reset'

💡 選び方のヒント: 多くの場合、'play none none reverse' が最も自然な動きになります。ユーザーがスクロールを戻したときにアニメーションも巻き戻るため、直感的な体験を提供できます。

scrub:スクロールに同期したアニメーション

scrub は、ScrollTriggerの最も強力な機能の一つです。通常のアニメーションは開始したら自動的に最後まで再生されますが、scrubを使うとアニメーションの進行をスクロール位置に完全に同期させることができます。

これにより、ユーザーがスクロールを止めるとアニメーションも止まり、逆方向にスクロールするとアニメーションも逆再生されます。プログレスバー、視差効果、インタラクティブなストーリーテリングなどに最適です。


基本的な使い方

JavaScript
gsap.to('.box', {
  x: 500,
  rotation: 360,
  scrollTrigger: {
    trigger: '.container',
    start: 'top top',
    end: 'bottom bottom',
    scrub: true,  // スクロールに同期
  },
});

scrub の値

scrubにはtrue以外にも数値を指定できます。数値を指定するとスムージング(遅延)効果が追加され、より滑らかな動きになります。

説明動きの特徴
trueスクロールに完全同期即座に追従、カクカクしやすい
0.50.5秒のスムージングわずかに滑らか
11秒のスムージング自然な追従
22秒のスムージングゆったりとした追従

スムージングを入れると、スクロールを止めてもアニメーションが滑らかに目標位置まで追従します。ユーザー体験を向上させるため、scrub: 1 程度のスムージングを入れることをおすすめします。


デモ:Scrub

スクロールすると、アニメーションがスクロール位置に同期します。スクロールを止めると、アニメーションも止まることを確認してください。

Loading...

このデモでは、スクロールに連動してボックスが移動・回転します。スクロール速度を変えたり、逆方向にスクロールしたりして、scrubの動作を体験してみてください。

pin:要素をビューポートに固定

pin は、スクロール中に要素をビューポートに固定(ピン留め)する機能です。AppleやNikeのようなプレミアムなスクロール体験でよく見られる演出を簡単に実装できます。

ピン留めは、製品紹介ページ、ストーリーテリング、複数ステップの説明など、ユーザーの注目を集めたい場面で特に効果的です。要素が画面に固定されている間に、その中のコンテンツをアニメーションさせることで、インパクトのある演出が可能になります。


基本的な使い方

JavaScript
gsap.to('.content', {
  opacity: 1,
  scrollTrigger: {
    trigger: '.section',
    start: 'top top',
    end: '+=500',     // 500pxスクロールするまで固定
    pin: true,        // .sectionをピン留め
    scrub: 1,
  },
});

この例では、.section要素がビューポートのトップに到達すると固定され、500pxスクロールするまでその位置に留まります。その間、.contentのopacityがアニメーションします。


注意点

pinを使う際は、以下の点に注意してください。

1. ピン留めする要素自体をアニメーションしない

ピン留め中の要素の位置やサイズを変更すると、ScrollTriggerの計算がずれて予期しない動作になります。代わりに、内側の要素をアニメーションしましょう。

JavaScript
// ❌ 悪い例:ピン留め要素自体をアニメーション
gsap.to('.pinned-section', { x: 100, ... });
 
// ✅ 良い例:内側の要素をアニメーション
gsap.to('.pinned-section .inner-content', { x: 100, ... });

2. pinSpacing の理解

デフォルトでは、ピン留め中に後続コンテンツが要素の後ろに流れないよう、余白が自動で追加されます。これにより、ピン留めが終わった後のレイアウトが崩れません。

  • pinSpacing: true(デフォルト): 余白を追加
  • pinSpacing: false: 余白を無効化(特殊な演出時に使用)

デモ:Pin

スクロールすると、セクションが固定され、コンテンツが順番に表示されます。ピン留めの開始・終了のタイミングを体験してください。

Loading...

このデモでは、セクションがビューポートに固定されている間に、複数のコンテンツが順番にフェードインします。scrubと組み合わせることで、スクロール量に応じた滑らかな表示切り替えを実現しています。

markers:デバッグ用マーカー

markers は、ScrollTriggerの開発時に欠かせないデバッグツールです。startendの位置が視覚的に表示されるため、「なぜアニメーションが意図したタイミングで動かないのか」 という問題を素早く解決できます。


基本的な使い方

JavaScript
scrollTrigger: {
  trigger: '.box',
  start: 'top 80%',
  end: 'bottom 20%',
  markers: true,  // マーカーを表示
}

マーカーを有効にすると、画面に以下が表示されます:

  • start: アニメーション開始位置(緑色のライン)
  • end: アニメーション終了位置(赤色のライン)
  • scroller-start / scroller-end: ビューポート側の位置

マーカーのカスタマイズ

複数のScrollTriggerを同時にデバッグする場合、マーカーの色やサイズをカスタマイズすると区別しやすくなります。

JavaScript
markers: {
  startColor: 'green',
  endColor: 'red',
  fontSize: '18px',
  fontWeight: 'bold',
  indent: 20,  // マーカーの水平位置をずらす
}

⚠️ 重要: 本番環境では必ず markers を削除またはfalseに設定してください。マーカーが残っていると、ユーザーに見えてしまい、パフォーマンスにも影響します。

React/Next.js での使い方

React や Next.js でScrollTriggerを使う場合は、適切なクリーンアップ処理が非常に重要です。これを怠ると、コンポーネントのアンマウント時にScrollTriggerインスタンスが残り、メモリリークや予期しない動作の原因になります。

GSAPはgsap.context()という便利な機能を提供しており、これを使うことでクリーンアップを簡単に行えます。


基本的な実装パターン

TypeScript
'use client';
 
import { useEffect, useRef } from 'react';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
 
gsap.registerPlugin(ScrollTrigger);
 
export function MyComponent() {
  const containerRef = useRef<HTMLDivElement>(null);
 
  useEffect(() => {
    // gsap.context を使ってスコープを限定
    const ctx = gsap.context(() => {
      gsap.to('.box', {
        x: 200,
        scrollTrigger: {
          trigger: '.box',
          start: 'top 80%',
          scrub: true,
        },
      });
    }, containerRef); // このコンテナ内のみ対象
 
    // クリーンアップ
    return () => ctx.revert();
  }, []);
 
  return (
    <div ref={containerRef}>
      <div className="box">Animate me</div>
    </div>
  );
}

重要なポイント

1. gsap.context() でスコープを限定

第2引数にref(またはDOM要素)を渡すと、そのコンテナ内の要素のみがアニメーションの対象になります。これにより、他のコンポーネントのアニメーションに影響を与えません。

2. ctx.revert() でクリーンアップ

useEffectのクリーンアップ関数でctx.revert()を呼び出すことで、コンポーネントがアンマウントされたときにすべてのアニメーションとScrollTriggerインスタンスが自動的に削除されます。

3. 'use client' を忘れずに(App Router の場合)

Next.js App Routerでは、GSAPはクライアントサイドでのみ動作するため、コンポーネントの先頭に'use client'ディレクティブが必要です。

4. registerPlugin() はアプリ全体で一度だけ

gsap.registerPlugin(ScrollTrigger)は、アプリケーション全体で一度だけ呼び出せば十分です。レイアウトコンポーネントや専用のセットアップファイルで呼び出すのがおすすめです。

まとめ

この記事では、GSAP ScrollTrigger の基本を学びました。

学んだこと

  • セットアップ方法
  • start / end でトリガー位置を指定
  • toggleActions でアニメーションの動作を制御
  • scrub でスクロールに同期
  • pin で要素を固定
  • markers でデバッグ
  • React/Next.js での使い方

次のステップ

応用編では、以下の高度なテクニックを紹介します:

  • タイムラインとの組み合わせ
  • パララックス効果
  • 水平スクロール
  • スナップ機能
  • stagger アニメーション

参考リンク