09. GSAPアニメーション

この章では、GSAPを使ったアニメーションを学びます。

GSAPは、Web制作のアニメーションでよく使われるJavaScriptライブラリです。CSSだけでは管理しづらい複雑な動き、順番に動くファーストビュー演出、スクロール連動アニメーションなどで使われます。

ただし、GSAPは「何でも派手に動かすためのもの」ではありません。情報を読みやすくし、ブランドの印象を高め、ユーザー体験を邪魔しない範囲で使うことが大切です。

GSAPを使う場面

まず、GSAPを使うべき場面を整理しましょう。

やりたいことおすすめ
hoverで色を変えるCSS
単純なフェードインCSS + Intersection Observer
複数要素を順番に動かすGSAP
ファーストビューで文字や画像を順番に表示するGSAP Timeline
スクロール位置に連動して動かすGSAP ScrollTrigger
複雑なタイムライン演出GSAP

小さな動きならCSSで十分です。

一方で、複数の要素を細かいタイミングで制御したい場合は、GSAPの方が読みやすく、調整もしやすくなります。

GSAPの導入

npmを使う環境では、GSAPをインストールして読み込みます。

npm
npm install gsap
JavaScript
import { gsap } from "gsap";

静的なHTML制作では、CDNで読み込む場合もあります。

CDN
<script src="https://cdn.jsdelivr.net/npm/gsap/dist/gsap.min.js"></script>

この教材では、コードの考え方を理解するために、gsapが使える状態になっている前提で例を見ていきます。

gsap.to

gsap.toは、現在の状態から指定した状態へアニメーションします。

HTML
<div class="box js-box">Box</div>
gsap.to
gsap.to(".js-box", {
    x: 100,
    opacity: 0.5,
    duration: 1,
});

この例では、.js-boxが現在位置から右に100px動き、透明度が0.5になります。

よく使うプロパティは次の通りです。

プロパティ役割
x横方向の移動
y縦方向の移動
opacity透明度
scale拡大縮小
rotation回転
durationアニメーション時間
delay開始までの待ち時間
ease動きの緩急

gsap.from

gsap.fromは、指定した状態から現在の状態へアニメーションします。

gsap.from
gsap.from(".js-title", {
    y: 40,
    opacity: 0,
    duration: 0.8,
    ease: "power2.out",
});

この例では、.js-titleが「下に40px、透明」な状態から、CSSで定義された通常の状態へ戻ります。

ファーストビューのテキスト表示、セクション見出しの表示などでよく使います。

gsap.fromTo

gsap.fromToは、開始状態と終了状態の両方を指定します。

gsap.fromTo
gsap.fromTo(
    ".js-image",
    {
        clipPath: "inset(0 100% 0 0)",
    },
    {
        clipPath: "inset(0 0% 0 0)",
        duration: 1,
        ease: "power3.out",
    }
);

開始状態と終了状態を明確にしたい時に使います。

CSSや直前の状態に依存させたくない演出では便利です。

duration、delay、ease

GSAPでは、時間や緩急をオブジェクトで指定します。

durationとdelay
gsap.from(".js-heading", {
    y: 32,
    opacity: 0,
    duration: 0.8,
    delay: 0.2,
    ease: "power2.out",
});

durationは秒単位です。

duration: 0.8なら0.8秒、delay: 0.2なら0.2秒待ってから開始します。

easeは動きの緩急です。

easeの例
gsap.to(".js-button", {
    scale: 1.05,
    duration: 0.3,
    ease: "power2.out",
});

stagger

staggerは、複数要素を少しずつずらして動かす設定です。

HTML
<ul class="feature-list">
    <li class="js-feature-item">特徴1</li>
    <li class="js-feature-item">特徴2</li>
    <li class="js-feature-item">特徴3</li>
</ul>
stagger
gsap.from(".js-feature-item", {
    y: 24,
    opacity: 0,
    duration: 0.6,
    stagger: 0.12,
    ease: "power2.out",
});

stagger: 0.12は、各要素の開始タイミングを0.12秒ずつずらすという意味です。

カード一覧、ナビゲーション、ファーストビューのテキストなどでよく使います。

Timeline

複数のアニメーションを順番に管理したい時は、Timelineを使います。

Timeline
const timeline = gsap.timeline();

timeline
    .from(".js-logo", {
        y: 20,
        opacity: 0,
        duration: 0.5,
    })
    .from(".js-copy", {
        y: 32,
        opacity: 0,
        duration: 0.7,
    })
    .from(".js-button", {
        y: 24,
        opacity: 0,
        duration: 0.5,
    });

Timelineに追加したアニメーションは、基本的に順番に再生されます。

ファーストビューの演出では、とてもよく使います。

Timelineの重なり

アニメーションを少し重ねたい場合は、位置パラメータを使います。

少し重ねる
const timeline = gsap.timeline();

timeline
    .from(".js-title", {
        y: 32,
        opacity: 0,
        duration: 0.8,
    })
    .from(
        ".js-lead",
        {
            y: 24,
            opacity: 0,
            duration: 0.6,
        },
        "-=0.3"
    );

"-=0.3"は、前のアニメーションが終わる0.3秒前に開始するという意味です。

こうすると、動きがぶつ切りにならず自然につながります。

ScrollTrigger

ScrollTriggerは、スクロールに応じてGSAPアニメーションを実行するプラグインです。

npm環境では、GSAPとScrollTriggerを読み込み、登録します。

ScrollTriggerの読み込み
import { gsap } from "gsap";
import { ScrollTrigger } from "gsap/ScrollTrigger";

gsap.registerPlugin(ScrollTrigger);

gsap.registerPlugin(ScrollTrigger)を忘れると、ビルド環境によっては本番で動かないことがあります。

ScrollTriggerの基本形

ScrollTrigger
gsap.from(".js-section-title", {
    y: 40,
    opacity: 0,
    duration: 0.8,
    ease: "power2.out",
    scrollTrigger: {
        trigger: ".js-section-title",
        start: "top 80%",
    },
});

triggerは、どの要素をきっかけにするかです。

start: "top 80%"は、トリガー要素の上端が画面の80%の位置に来たら開始する、という意味です。

markers

開発中は、markers: trueを使うと開始位置や終了位置を確認できます。

markers
gsap.from(".js-section-title", {
    y: 40,
    opacity: 0,
    scrollTrigger: {
        trigger: ".js-section-title",
        start: "top 80%",
        markers: true,
    },
});

本番公開前には、markersを消します。

scrub

scrubを使うと、スクロール量に合わせてアニメーションが進みます。

scrub
gsap.to(".js-image", {
    y: -80,
    ease: "none",
    scrollTrigger: {
        trigger: ".js-image",
        start: "top bottom",
        end: "bottom top",
        scrub: true,
    },
});

パララックス風の動きなどで使います。

scrubを使う時は、ease: "none"にすることが多いです。スクロール量と動きを素直に対応させるためです。

pin

pinを使うと、スクロール中に要素を固定できます。

pin
gsap.to(".js-pin-content", {
    x: -300,
    scrollTrigger: {
        trigger: ".js-pin-section",
        start: "top top",
        end: "+=800",
        scrub: true,
        pin: true,
    },
});

横スクロール風演出や、セクション固定演出で使います。

ただし、pinはレイアウトへの影響が大きいので、実務では慎重に使います。

レスポンシブ対応

PCだけGSAP演出を入れ、スマホでは軽くしたいことがあります。

その場合は、matchMediaを使って条件分岐します。

画面幅で分ける
const mediaQuery = window.matchMedia("(min-width: 769px)");

if (mediaQuery.matches) {
    gsap.from(".js-hero-image", {
        scale: 1.1,
        opacity: 0,
        duration: 1,
        ease: "power2.out",
    });
}

ScrollTriggerでも画面幅によって設定を変えることがあります。

実務では、スマホで動かす必要があるか、必ず確認しましょう。

prefers-reduced-motion

GSAPでも、アニメーションを減らしたいユーザーへの配慮が必要です。

reduced motion対応
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

if (!prefersReducedMotion) {
    gsap.from(".js-title", {
        y: 32,
        opacity: 0,
        duration: 0.8,
    });
}

大きく動く演出、長い演出、スクロール連動演出では特に意識しましょう。

小さな実装例: ファーストビュー演出

ファーストビューで、ロゴ、見出し、リード文、ボタンを順番に表示する例です。

HTML
<section class="hero">
    <p class="hero-label js-hero-label">Web Production</p>
    <h1 class="hero-title js-hero-title">伝わるWebサイトを作る</h1>
    <p class="hero-lead js-hero-lead">設計から実装まで丁寧に支援します。</p>
    <a class="hero-button js-hero-button" href="#contact">お問い合わせ</a>
</section>
JavaScript
const prefersReducedMotion = window.matchMedia("(prefers-reduced-motion: reduce)").matches;

if (!prefersReducedMotion) {
    const timeline = gsap.timeline({
        defaults: {
            duration: 0.7,
            ease: "power2.out",
        },
    });

    timeline
        .from(".js-hero-label", {
            y: 20,
            opacity: 0,
        })
        .from(
            ".js-hero-title",
            {
                y: 32,
                opacity: 0,
            },
            "-=0.35"
        )
        .from(
            ".js-hero-lead",
            {
                y: 24,
                opacity: 0,
            },
            "-=0.25"
        )
        .from(
            ".js-hero-button",
            {
                y: 16,
                opacity: 0,
            },
            "-=0.2"
        );
}

Timelineのdefaultsを使うと、共通のdurationeaseをまとめられます。

小さな実装例: セクション見出し

ScrollTriggerで、セクション見出しが画面に入ったら表示します。

HTML
<h2 class="section-title js-section-title">サービス</h2>
JavaScript
gsap.utils.toArray(".js-section-title").forEach((title) => {
    gsap.from(title, {
        y: 32,
        opacity: 0,
        duration: 0.8,
        ease: "power2.out",
        scrollTrigger: {
            trigger: title,
            start: "top 80%",
        },
    });
});

gsap.utils.toArrayを使うと、複数要素を配列として扱いやすくなります。

GSAP使用時の注意点

GSAPを使う時は、次の点に注意します。

  • アニメーションを長くしすぎない
  • widthheightより、できるだけtransformopacityを使う
  • スマホで重くならないか確認する
  • ScrollTriggerのmarkersを本番に残さない
  • 画像やWebフォント読み込み後に位置がずれる場合がある
  • pinを使う演出は、ページ全体のスクロール体験を確認する
  • prefers-reduced-motionを考慮する

アニメーションは、実装した時点では気持ちよく見えても、何度も使うユーザーにとっては負担になることがあります。

動きの量、時間、頻度を調整しましょう。

よくある失敗

GSAPでよくある失敗を整理しておきます。

  • CSSで初期状態を隠し、JavaScriptが失敗した時にずっと見えない
  • ScrollTriggerを読み込んだがregisterPluginしていない
  • markers: trueを本番に残す
  • 同じ要素に複数のScrollTriggerを重ねて、動きが競合する
  • スマホでもPCと同じ重い演出を入れてしまう
  • pinの影響でアンカーリンクや後続セクションがずれる
  • アニメーションが情報を読む邪魔になっている

実務では、見た目だけでなく「壊れにくさ」と「読みやすさ」も品質です。

この章のまとめ

この章では、GSAPの基本を学びました。

  • GSAPは、複雑なタイミング制御やスクロール連動演出に向いている
  • 単純なhoverやフェードならCSSで十分な場面も多い
  • gsap.toは現在から指定状態へ、gsap.fromは指定状態から現在へ動く
  • staggerで複数要素を順番に動かせる
  • Timelineを使うと、複数の演出を順番に管理しやすい
  • ScrollTriggerでは、triggerstartendscrubpinを理解する
  • 実務では、パフォーマンス、スマホ表示、reduced motion、本番前の確認が重要

次の章では、Web制作で頻出するスライダーをSplideで実装します。