
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からモダンブラウザまで同じ動作を保証 |
| 直感的なAPI | gsap.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ファイルに直接スクリプトタグを追加する最もシンプルな方法です。プロトタイピングや小規模なプロジェクトに適しています。
<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などのモダンなフレームワークを使用している場合は、パッケージマネージャーでインストールします。
npm install gsapインストール後、以下のようにインポートして使用します。重要なのはgsap.registerPlugin()でScrollTriggerを登録することです。これを忘れるとScrollTriggerが動作しません。
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
// プラグインを登録(必須!)
gsap.registerPlugin(ScrollTrigger);ポイント: registerPlugin()はアプリケーション全体で一度だけ呼び出せば十分です。Reactの場合は、ルートコンポーネントやレイアウトコンポーネントで呼び出すのがおすすめです。
基本的なスクロールアニメーション
最もシンプルな例として、要素が画面に入ったらアニメーションを開始する実装を見てみましょう。ScrollTriggerの魅力は、わずか数行のコードで複雑なスクロール演出を実現できることです。
最小構成
ScrollTriggerの最小構成は驚くほどシンプルです。通常のGSAPアニメーションにscrollTriggerプロパティを追加するだけです。
gsap.to('.box', {
scrollTrigger: '.box', // この要素がビューポートに入ったらトリガー
x: 500
});たったこれだけで、.box 要素が画面に入ったら右に500px移動するアニメーションが実装できます。scrollTriggerに文字列(セレクタ)を渡すと、その要素がビューポートに入ったときにアニメーションが開始されます。
より詳細な設定
実際のプロジェクトでは、アニメーションのタイミングや動作をより細かく制御したい場合が多いでしょう。scrollTriggerにオブジェクトを渡すことで、詳細な設定が可能になります。
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 | アニメーションが終了する位置 |
toggleActions | 4つのタイミング(enter, leave, enterBack, leaveBack)での動作を指定 |
markers | デバッグ用のマーカーを表示(開発時に便利) |
デモ:基本的なアニメーション
スクロールして、各要素のアニメーションを確認してください。移動、回転、フェードインなど、基本的なアニメーションパターンを確認できます。
このデモでは3種類のアニメーションを実装しています。それぞれのボックスが画面に入ると、設定されたアニメーションが再生されます。
start と end の指定方法
start と end は、アニメーションの開始位置と終了位置を指定する最も重要なプロパティです。この設定を理解すれば、思い通りのタイミングでアニメーションを制御できます。
基本構文
startとendは、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' |
よくある設定パターン
実際のプロジェクトでよく使用されるパターンをいくつか紹介します。
// 要素の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 | 何もしない | 特定のタイミングを無視 |
よく使うパターン
// 入ったら再生、戻ったら逆再生(最もよく使う)
toggleActions: 'play none none reverse'
// 入るたびに最初から再生
toggleActions: 'restart none none none'
// 出たらリセット、戻ったら再生(毎回フレッシュな状態で見せる)
toggleActions: 'play reset play reset'💡 選び方のヒント: 多くの場合、'play none none reverse' が最も自然な動きになります。ユーザーがスクロールを戻したときにアニメーションも巻き戻るため、直感的な体験を提供できます。
scrub:スクロールに同期したアニメーション
scrub は、ScrollTriggerの最も強力な機能の一つです。通常のアニメーションは開始したら自動的に最後まで再生されますが、scrubを使うとアニメーションの進行をスクロール位置に完全に同期させることができます。
これにより、ユーザーがスクロールを止めるとアニメーションも止まり、逆方向にスクロールするとアニメーションも逆再生されます。プログレスバー、視差効果、インタラクティブなストーリーテリングなどに最適です。
基本的な使い方
gsap.to('.box', {
x: 500,
rotation: 360,
scrollTrigger: {
trigger: '.container',
start: 'top top',
end: 'bottom bottom',
scrub: true, // スクロールに同期
},
});scrub の値
scrubにはtrue以外にも数値を指定できます。数値を指定するとスムージング(遅延)効果が追加され、より滑らかな動きになります。
| 値 | 説明 | 動きの特徴 |
|---|---|---|
true | スクロールに完全同期 | 即座に追従、カクカクしやすい |
0.5 | 0.5秒のスムージング | わずかに滑らか |
1 | 1秒のスムージング | 自然な追従 |
2 | 2秒のスムージング | ゆったりとした追従 |
スムージングを入れると、スクロールを止めてもアニメーションが滑らかに目標位置まで追従します。ユーザー体験を向上させるため、scrub: 1 程度のスムージングを入れることをおすすめします。
デモ:Scrub
スクロールすると、アニメーションがスクロール位置に同期します。スクロールを止めると、アニメーションも止まることを確認してください。
このデモでは、スクロールに連動してボックスが移動・回転します。スクロール速度を変えたり、逆方向にスクロールしたりして、scrubの動作を体験してみてください。
pin:要素をビューポートに固定
pin は、スクロール中に要素をビューポートに固定(ピン留め)する機能です。AppleやNikeのようなプレミアムなスクロール体験でよく見られる演出を簡単に実装できます。
ピン留めは、製品紹介ページ、ストーリーテリング、複数ステップの説明など、ユーザーの注目を集めたい場面で特に効果的です。要素が画面に固定されている間に、その中のコンテンツをアニメーションさせることで、インパクトのある演出が可能になります。
基本的な使い方
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の計算がずれて予期しない動作になります。代わりに、内側の要素をアニメーションしましょう。
// ❌ 悪い例:ピン留め要素自体をアニメーション
gsap.to('.pinned-section', { x: 100, ... });
// ✅ 良い例:内側の要素をアニメーション
gsap.to('.pinned-section .inner-content', { x: 100, ... });2. pinSpacing の理解
デフォルトでは、ピン留め中に後続コンテンツが要素の後ろに流れないよう、余白が自動で追加されます。これにより、ピン留めが終わった後のレイアウトが崩れません。
pinSpacing: true(デフォルト): 余白を追加pinSpacing: false: 余白を無効化(特殊な演出時に使用)
デモ:Pin
スクロールすると、セクションが固定され、コンテンツが順番に表示されます。ピン留めの開始・終了のタイミングを体験してください。
このデモでは、セクションがビューポートに固定されている間に、複数のコンテンツが順番にフェードインします。scrubと組み合わせることで、スクロール量に応じた滑らかな表示切り替えを実現しています。
markers:デバッグ用マーカー
markers は、ScrollTriggerの開発時に欠かせないデバッグツールです。startとendの位置が視覚的に表示されるため、「なぜアニメーションが意図したタイミングで動かないのか」 という問題を素早く解決できます。
基本的な使い方
scrollTrigger: {
trigger: '.box',
start: 'top 80%',
end: 'bottom 20%',
markers: true, // マーカーを表示
}マーカーを有効にすると、画面に以下が表示されます:
- start: アニメーション開始位置(緑色のライン)
- end: アニメーション終了位置(赤色のライン)
- scroller-start / scroller-end: ビューポート側の位置
マーカーのカスタマイズ
複数のScrollTriggerを同時にデバッグする場合、マーカーの色やサイズをカスタマイズすると区別しやすくなります。
markers: {
startColor: 'green',
endColor: 'red',
fontSize: '18px',
fontWeight: 'bold',
indent: 20, // マーカーの水平位置をずらす
}⚠️ 重要: 本番環境では必ず markers を削除またはfalseに設定してください。マーカーが残っていると、ユーザーに見えてしまい、パフォーマンスにも影響します。
React/Next.js での使い方
React や Next.js でScrollTriggerを使う場合は、適切なクリーンアップ処理が非常に重要です。これを怠ると、コンポーネントのアンマウント時にScrollTriggerインスタンスが残り、メモリリークや予期しない動作の原因になります。
GSAPはgsap.context()という便利な機能を提供しており、これを使うことでクリーンアップを簡単に行えます。
基本的な実装パターン
'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 アニメーション