【コピペOK】実用的なGSAPアニメーション8選

目次

はじめに

今回は、現場で愛用されているGSAPを使って、コピペするだけで実装できる実用的なアニメーションを8つご紹介します。

基本的なフェードインから高度なScrollTriggerまで、段階的にスキルアップできる構成で解説していきます。

この記事を読み終える頃には、プロレベルのアニメーションをサイトに実装し、ユーザー体験を劇的に向上させることができるようになりますので、ぜひ最後まで読んでみてください。

GSAPの基本的な使い方は、以下の記事で解説していますので、あわせてご確認ください。

1. フェードイン

See the Pen Untitled by ryoma (@hwjgdjpk-the-decoder) on CodePen.

HTML

<div class="fade-container">
  <h2 class="fade-title">GSAP Fade In Animation</h2>
  <p class="fade-text">この文章がフェードインで表示されます</p>
  <div class="fade-box">ボックス要素</div>
</div>

CSS

.fade-container {
  max-width: 600px;
  margin: 50px auto;
  padding: 40px;
  text-align: center;
}

.fade-title {
  font-size: 2rem;
  margin-bottom: 20px;
  color: #333;
}

.fade-text {
  font-size: 1.1rem;
  line-height: 1.6;
  color: #666;
  margin-bottom: 30px;
}

.fade-box {
  width: 200px;
  height: 100px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  display: flex;
  align-items: center;
  justify-content: center;
  margin: 0 auto;
  border-radius: 10px;
  font-weight: bold;
}

JavaScript

// 基本のフェードイン
gsap.from(".fade-title", {
  duration: 1,
  y: 30,
  opacity: 0,
  ease: "power2.out"
});

gsap.from(".fade-text", {
  duration: 1,
  y: 30,
  opacity: 0,
  ease: "power2.out",
  delay: 0.3
});

gsap.from(".fade-box", {
  duration: 1,
  scale: 0.8,
  opacity: 0,
  ease: "back.out(1.7)",
  delay: 0.6
});

2. カードホバーエフェクト

See the Pen Untitled by ryoma (@hwjgdjpk-the-decoder) on CodePen.

HTML

<div class="cards-container">
  <div class="hover-card">
    <div class="card-image">
      <img src="https://via.placeholder.com/300x200" alt="Card Image">
    </div>
    <div class="card-content">
      <h3>プロジェクト タイトル</h3>
      <p>ここに説明文が入ります。GSAPを使用した美しいホバーエフェクトです。</p>
      <button class="card-button">詳細を見る</button>
    </div>
  </div>
</div>

CSS

.cards-container {
  display: flex;
  justify-content: center;
  padding: 50px;
}

.hover-card {
  width: 320px;
  background: white;
  border-radius: 15px;
  box-shadow: 0 10px 30px rgba(0,0,0,0.1);
  overflow: hidden;
  cursor: pointer;
  transition: box-shadow 0.3s ease;
}

.card-image {
  width: 100%;
  height: 200px;
  overflow: hidden;
}

.card-image img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.card-content {
  padding: 25px;
}

.card-content h3 {
  margin: 0 0 15px;
  font-size: 1.4rem;
  color: #333;
}

.card-content p {
  margin: 0 0 20px;
  color: #666;
  line-height: 1.6;
}

.card-button {
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  color: white;
  border: none;
  padding: 12px 24px;
  border-radius: 25px;
  cursor: pointer;
  font-weight: 500;
  transition: transform 0.2s ease;
}

JavaScript

// カードホバーアニメーション
const cards = document.querySelectorAll('.hover-card');

cards.forEach(card => {
  const image = card.querySelector('.card-image img');
  const button = card.querySelector('.card-button');

  // マウスオーバー時
  card.addEventListener('mouseenter', () => {
    gsap.to(card, {
      duration: 0.3,
      y: -10,
      rotationX: 5,
      rotationY: 5,
      scale: 1.02,
      ease: "power2.out",
      transformPerspective: 1000
    });

    gsap.to(image, {
      duration: 0.5,
      scale: 1.1,
      ease: "power2.out"
    });

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

  // マウスアウト時
  card.addEventListener('mouseleave', () => {
    gsap.to(card, {
      duration: 0.3,
      y: 0,
      rotationX: 0,
      rotationY: 0,
      scale: 1,
      ease: "power2.out"
    });

    gsap.to(image, {
      duration: 0.5,
      scale: 1,
      ease: "power2.out"
    });

    gsap.to(button, {
      duration: 0.3,
      scale: 1,
      ease: "power2.out"
    });
  });
});

3. テキストアニメーション

See the Pen Untitled by ryoma (@hwjgdjpk-the-decoder) on CodePen.

HTML

<div class="text-animation-container">
  <h1 class="animated-title" data-text="Beautiful Typography">Beautiful Typography</h1>
  <p class="animated-paragraph">このテキストは一文字ずつアニメーションします。GSAPの強力な機能を活用して、印象的な文字演出を実現できます。</p>
</div>

CSS

.text-animation-container {
  max-width: 800px;
  margin: 100px auto;
  text-align: center;
  padding: 40px;
}

.animated-title {
  font-size: 3rem;
  font-weight: 700;
  color: #333;
  margin-bottom: 40px;
  overflow: hidden;
}

.animated-paragraph {
  font-size: 1.2rem;
  line-height: 1.8;
  color: #666;
  overflow: hidden;
}

.char {
  display: inline-block;
}

JavaScript

// テキストを文字単位に分割する関数
function splitText(element) {
  const text = element.textContent;
  element.innerHTML = '';

  text.split('').forEach(char => {
    const span = document.createElement('span');
    span.className = 'char';
    span.textContent = char === ' ' ? '\u00A0' : char; // スペースの処理
    element.appendChild(span);
  });
}

// タイトルのアニメーション
const title = document.querySelector('.animated-title');
splitText(title);

gsap.from('.animated-title .char', {
  duration: 0.8,
  y: 100,
  opacity: 0,
  rotationX: -90,
  stagger: 0.05,
  ease: "back.out(1.7)",
  transformOrigin: "50% 50% -50px"
});

// 段落のアニメーション
const paragraph = document.querySelector('.animated-paragraph');
splitText(paragraph);

gsap.from('.animated-paragraph .char', {
  duration: 0.6,
  y: 50,
  opacity: 0,
  stagger: 0.02,
  ease: "power2.out",
  delay: 1
});

// カラフルなテキストエフェクト
gsap.to('.animated-title .char', {
  duration: 2,
  color: () => {
    const colors = ['#667eea', '#764ba2', '#f093fb', '#f5576c'];
    return colors[Math.floor(Math.random() * colors.length)];
  },
  stagger: 0.1,
  repeat: -1,
  yoyo: true,
  delay: 2
});

4. ScrollTrigger基本

See the Pen Untitled by ryoma (@hwjgdjpk-the-decoder) on CodePen.

HTML

<div class="scroll-container">
  <section class="scroll-section">
    <h2 class="scroll-title">スクロールで表示されるタイトル</h2>
    <div class="scroll-content">
      <div class="scroll-item">
        <div class="item-icon">📱</div>
        <h3>モバイルファースト</h3>
        <p>レスポンシブデザインに対応した、モバイル優先の設計思想です。</p>
      </div>

      <div class="scroll-item">
        <div class="item-icon">⚡</div>
        <h3>高速パフォーマンス</h3>
        <p>最適化されたコードによる、高速な表示速度を実現します。</p>
      </div>

      <div class="scroll-item">
        <div class="item-icon">🎨</div>
        <h3>美しいデザイン</h3>
        <p>ユーザビリティを考慮した、直感的で美しいインターフェース。</p>
      </div>
    </div>
  </section>
</div>

CSS

.scroll-container {
  min-height: 200vh; /* スクロール効果を確認するため */
}

.scroll-section {
  max-width: 1000px;
  margin: 100px auto;
  padding: 80px 40px;
}

.scroll-title {
  font-size: 2.5rem;
  text-align: center;
  margin-bottom: 60px;
  color: #333;
}

.scroll-content {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 40px;
}

.scroll-item {
  background: white;
  padding: 40px;
  border-radius: 15px;
  box-shadow: 0 15px 35px rgba(0,0,0,0.1);
  text-align: center;
}

.item-icon {
  font-size: 3rem;
  margin-bottom: 20px;
}

.scroll-item h3 {
  font-size: 1.5rem;
  margin-bottom: 15px;
  color: #333;
}

.scroll-item p {
  color: #666;
  line-height: 1.6;
}

JavaScript

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

// タイトルのスクロールアニメーション
gsap.from(".scroll-title", {
  scrollTrigger: {
    trigger: ".scroll-title",
    start: "top 80%",
    end: "bottom 20%",
    toggleActions: "play none none reverse"
  },
  duration: 1,
  y: 50,
  opacity: 0,
  ease: "power2.out"
});

// アイテムの順次表示
gsap.from(".scroll-item", {
  scrollTrigger: {
    trigger: ".scroll-content",
    start: "top 70%",
    end: "bottom 30%",
    toggleActions: "play none none reverse"
  },
  duration: 0.8,
  y: 80,
  opacity: 0,
  stagger: 0.2,
  ease: "power2.out"
});

// アイコンの回転アニメーション
gsap.from(".item-icon", {
  scrollTrigger: {
    trigger: ".scroll-content",
    start: "top 60%",
    end: "bottom 40%",
    toggleActions: "play none none reverse"
  },
  duration: 1,
  rotation: 360,
  scale: 0,
  stagger: 0.2,
  ease: "back.out(1.7)"
});

5. パララックス効果

See the Pen Untitled by ryoma (@hwjgdjpk-the-decoder) on CodePen.

HTML

<div class="parallax-container">
  <div class="parallax-bg"></div>
  <div class="parallax-content">
    <h1 class="parallax-title">Parallax Magic</h1>
    <p class="parallax-text">背景とコンテンツが異なる速度で動く、美しいパララックス効果です。</p>
    <div class="parallax-elements">
      <div class="floating-element element-1">○</div>
      <div class="floating-element element-2">△</div>
      <div class="floating-element element-3">□</div>
    </div>
  </div>
</div>

CSS

.parallax-container {
  position: relative;
  height: 100vh;
  overflow: hidden;
  display: flex;
  align-items: center;
  justify-content: center;
}

.parallax-bg {
  position: absolute;
  top: -20%;
  left: -20%;
  width: 140%;
  height: 140%;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 50%, #f093fb 100%);
  background-size: 400% 400%;
  animation: gradientShift 10s ease infinite;
}

.parallax-content {
  position: relative;
  text-align: center;
  color: white;
  z-index: 2;
}

.parallax-title {
  font-size: 4rem;
  font-weight: 700;
  margin-bottom: 20px;
  text-shadow: 0 4px 8px rgba(0,0,0,0.3);
}

.parallax-text {
  font-size: 1.3rem;
  margin-bottom: 40px;
  text-shadow: 0 2px 4px rgba(0,0,0,0.3);
}

.parallax-elements {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  pointer-events: none;
}

.floating-element {
  position: absolute;
  font-size: 2rem;
  color: rgba(255,255,255,0.6);
  font-weight: bold;
}

.element-1 {
  top: 20%;
  left: 10%;
}

.element-2 {
  top: 70%;
  right: 15%;
}

.element-3 {
  top: 40%;
  right: 30%;
}

@keyframes gradientShift {
  0%, 100% { background-position: 0% 50%; }
  50% { background-position: 100% 50%; }
}

JavaScript

// パララックス効果のセットアップ
gsap.registerPlugin(ScrollTrigger);

// 背景のパララックス
gsap.to(".parallax-bg", {
  yPercent: -50,
  ease: "none",
  scrollTrigger: {
    trigger: ".parallax-container",
    start: "top bottom",
    end: "bottom top",
    scrub: true
  }
});

// コンテンツのパララックス
gsap.to(".parallax-content", {
  yPercent: -30,
  ease: "none",
  scrollTrigger: {
    trigger: ".parallax-container",
    start: "top bottom",
    end: "bottom top",
    scrub: true
  }
});

// 浮遊要素のアニメーション
gsap.to(".floating-element", {
  y: "random(-100, 100)",
  x: "random(-50, 50)",
  rotation: "random(-180, 180)",
  duration: "random(3, 6)",
  ease: "sine.inOut",
  repeat: -1,
  yoyo: true,
  stagger: {
    amount: 2,
    from: "random"
  }
});

// 要素別のパララックス速度
gsap.to(".element-1", {
  yPercent: -80,
  ease: "none",
  scrollTrigger: {
    trigger: ".parallax-container",
    start: "top bottom",
    end: "bottom top",
    scrub: true
  }
});

gsap.to(".element-2", {
  yPercent: -60,
  ease: "none",
  scrollTrigger: {
    trigger: ".parallax-container",
    start: "top bottom", 
    end: "bottom top",
    scrub: true
  }
});

gsap.to(".element-3", {
  yPercent: -40,
  ease: "none",
  scrollTrigger: {
    trigger: ".parallax-container",
    start: "top bottom",
    end: "bottom top",
    scrub: true
  }
});

6. モーフィング(変形)アニメーション

See the Pen Untitled by ryoma (@hwjgdjpk-the-decoder) on CodePen.

HTML

<div class="morph-container">
  <div class="morph-shapes">
    <div class="morph-shape shape-1"></div>
    <div class="morph-shape shape-2"></div>
    <div class="morph-shape shape-3"></div>
  </div>

  <div class="morph-svg">
    <svg width="200" height="200" viewBox="0 0 200 200">
      <path id="morphPath" d="M100,50 Q150,50 150,100 Q150,150 100,150 Q50,150 50,100 Q50,50 100,50 Z" fill="#667eea"/>
    </svg>
  </div>

  <h2 class="morph-title">Shape Morphing</h2>
</div>

CSS

.morph-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 80px 40px;
  min-height: 100vh;
  background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
}

.morph-shapes {
  display: flex;
  gap: 40px;
  margin-bottom: 60px;
}

.morph-shape {
  width: 80px;
  height: 80px;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}

.shape-1 {
  border-radius: 50%;
}

.shape-2 {
  border-radius: 0;
}

.shape-3 {
  border-radius: 20px;
}

.morph-svg {
  margin-bottom: 40px;
}

.morph-title {
  font-size: 2.5rem;
  color: #333;
  font-weight: 700;
}

JavaScript

// CSS図形のモーフィング
const tl = gsap.timeline({ repeat: -1, yoyo: true });

tl.to(".shape-1", {
  duration: 2,
  borderRadius: "0%",
  rotation: 45,
  scale: 1.2,
  ease: "power2.inOut"
})
.to(".shape-2", {
  duration: 2,
  borderRadius: "50%",
  rotation: 180,
  scale: 0.8,
  ease: "power2.inOut"
}, 0)
.to(".shape-3", {
  duration: 2,
  borderRadius: "0%",
  rotation: -90,
  scale: 1.1,
  ease: "power2.inOut"
}, 0);

// SVGパスのモーフィング
const morphPath = document.getElementById('morphPath');

const shapes = [
  "M100,50 Q150,50 150,100 Q150,150 100,150 Q50,150 50,100 Q50,50 100,50 Z", // 円
  "M100,20 L180,100 L100,180 L20,100 Z", // 菱形
  "M50,50 L150,50 L150,150 L50,150 Z", // 四角
  "M100,30 L130,70 L170,70 L140,100 L150,140 L100,120 L50,140 L60,100 L30,70 L70,70 Z" // 星
];

let currentShape = 0;

function morphToNextShape() {
  currentShape = (currentShape + 1) % shapes.length;

  gsap.to(morphPath, {
    duration: 2,
    attr: { d: shapes[currentShape] },
    ease: "power2.inOut"
  });
}

// 3秒ごとに形を変更
setInterval(morphToNextShape, 3000);

// タイトルのアニメーション
gsap.from(".morph-title", {
  duration: 1.5,
  y: 50,
  opacity: 0,
  ease: "elastic.out(1, 0.3)"
});

// 色の変化
gsap.to(".morph-shape", {
  duration: 4,
  background: "linear-gradient(135deg, #f093fb 0%, #f5576c 100%)",
  repeat: -1,
  yoyo: true,
  stagger: 0.5
});

7. インフィニットスクロール効果

See the Pen Untitled by ryoma (@hwjgdjpk-the-decoder) on CodePen.

HTML

<div class="infinite-container">
  <h2 class="infinite-heading">技術スタック</h2>

  <!-- 上段だけ残す -->
  <div class="infinite-scroll">
    <div class="scroll-content">
      <div class="scroll-item">React</div>
      <div class="scroll-item">Vue.js</div>
      <div class="scroll-item">Angular</div>
      <div class="scroll-item">Node.js</div>
      <div class="scroll-item">Python</div>
      <div class="scroll-item">TypeScript</div>
      <div class="scroll-item">JavaScript</div>
      <div class="scroll-item">HTML5</div>
      <div class="scroll-item">CSS3</div>
      <div class="scroll-item">GSAP</div>
    </div>
  </div>
</div>

CSS

/* 親コンテナ */
.infinite-container {
  padding: 80px 0;
  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  overflow: hidden;
}

/* 見出し */
.infinite-heading {
  text-align: center;
  color: #fff;
  font-size: 2.5rem;
  margin-bottom: 60px;
  font-weight: 700;
}

/* 無限スクロールのレール */
.infinite-scroll {
  white-space: nowrap;
  overflow: hidden;
  margin-bottom: 40px;
}

/* アイテムの並び */
.scroll-content {
  margin-left: 60px;
  display: inline-flex;
  align-items: center;
  gap: 60px;          /* アイテム間のスペース */
}

/* 各アイテム */
.scroll-item {
  background: rgba(255, 255, 255, 0.2);
  backdrop-filter: blur(10px);
  color: #fff;
  padding: 15px 30px;
  border-radius: 50px;
  font-weight: 600;
  font-size: 1.1rem;
  border: 1px solid rgba(255, 255, 255, 0.3);
  white-space: nowrap;
  min-width: fit-content;
}

JavaScript

function createInfiniteScroll() {
  document.querySelectorAll('.infinite-scroll').forEach(container => {
    const content = container.querySelector('.scroll-content');
    const clone   = content.cloneNode(true);
    container.appendChild(clone);

    const w = content.offsetWidth;          // 元コンテンツの幅

    // 両方同じ位置に重ねてスタート
    gsap.set([content, clone], { x: 0 });

    // w ピクセル左へ移動 → リピート
    const tl = gsap.timeline({ repeat: -1 }).to([content, clone], {
      x: -w,
      duration: 20,
      ease: 'none'
    });

    container.addEventListener('mouseenter', () => tl.pause());
    container.addEventListener('mouseleave', () => tl.resume());
  });
}

// アニメーション開始
window.addEventListener('load', createInfiniteScroll);

// ホバー効果と見出しアニメーションはそのまま
gsap.utils.toArray('.scroll-item').forEach(item => {
  item.addEventListener('mouseenter', () =>
    gsap.to(item, { scale: 1.1, background: 'rgba(255,255,255,.3)', duration: .3, ease: 'power2.out' })
  );
  item.addEventListener('mouseleave', () =>
    gsap.to(item, { scale: 1,   background: 'rgba(255,255,255,.2)', duration: .3, ease: 'power2.out' })
  );
});

gsap.from('.infinite-heading', { duration: 1, y: 50, opacity: 0, ease: 'power2.out' });

8. パーティクル効果

See the Pen Untitled by ryoma (@hwjgdjpk-the-decoder) on CodePen.

HTML

<div class="particle-container">
  <div class="particle-bg">
    <canvas id="particleCanvas"></canvas>
  </div>

  <div class="particle-content">
    <h1 class="particle-title">Innovation Hub</h1>
    <p class="particle-subtitle">次世代のWebエクスペリエンスを創造する</p>
    <button class="particle-button">詳細を見る</button>
  </div>
</div>

CSS

.particle-container {
  position: relative;
  height: 100vh;
  background: radial-gradient(ellipse at center, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}

.particle-bg {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
}

#particleCanvas {
  width: 100%;
  height: 100%;
}

.particle-content {
  position: relative;
  z-index: 2;
  text-align: center;
  color: white;
}

.particle-title {
  font-size: 4rem;
  font-weight: 700;
  margin-bottom: 20px;
  text-shadow: 0 4px 8px rgba(0,0,0,0.5);
}

.particle-subtitle {
  font-size: 1.5rem;
  margin-bottom: 40px;
  opacity: 0.9;
}

.particle-button {
  background: linear-gradient(45deg, #667eea, #764ba2);
  color: white;
  border: none;
  padding: 15px 40px;
  font-size: 1.1rem;
  border-radius: 50px;
  cursor: pointer;
  transition: transform 0.3s ease;
  box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
}

.particle-button:hover {
  transform: translateY(-2px);
  box-shadow: 0 12px 35px rgba(102, 126, 234, 0.4);
}

JavaScript

// Canvas セットアップ
const canvas = document.getElementById('particleCanvas');
const ctx = canvas.getContext('2d');

// Canvas サイズ設定
function resizeCanvas() {
  canvas.width = window.innerWidth;
  canvas.height = window.innerHeight;
}
resizeCanvas();
window.addEventListener('resize', resizeCanvas);

// パーティクルクラス
class Particle {
  constructor() {
    this.x = Math.random() * canvas.width;
    this.y = Math.random() * canvas.height;
    this.vx = (Math.random() - 0.5) * 2;
    this.vy = (Math.random() - 0.5) * 2;
    this.size = Math.random() * 3 + 1;
    this.opacity = Math.random() * 0.5 + 0.3;
    this.hue = Math.random() * 60 + 200; // 青系の色相
  }

  update() {
    this.x += this.vx;
    this.y += this.vy;

    // 画面端での反射
    if (this.x < 0 || this.x > canvas.width) this.vx *= -1;
    if (this.y < 0 || this.y > canvas.height) this.vy *= -1;

    // 境界内に収める
    this.x = Math.max(0, Math.min(canvas.width, this.x));
    this.y = Math.max(0, Math.min(canvas.height, this.y));
  }

  draw() {
    ctx.save();
    ctx.globalAlpha = this.opacity;
    ctx.fillStyle = `hsl(${this.hue}, 70%, 60%)`;
    ctx.beginPath();
    ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
    ctx.fill();
    ctx.restore();
  }
}

// パーティクル配列
const particles = [];
const particleCount = 100;

// パーティクル生成
for (let i = 0; i < particleCount; i++) {
  particles.push(new Particle());
}

// マウス位置
let mouse = { x: 0, y: 0 };

canvas.addEventListener('mousemove', (e) => {
  mouse.x = e.clientX;
  mouse.y = e.clientY;
});

// アニメーションループ
function animate() {
  ctx.clearRect(0, 0, canvas.width, canvas.height);

  particles.forEach((particle, index) => {
    particle.update();
    particle.draw();

    // マウスとの相互作用
    const dx = mouse.x - particle.x;
    const dy = mouse.y - particle.y;
    const distance = Math.sqrt(dx * dx + dy * dy);

    if (distance < 100) {
      const force = (100 - distance) / 100;
      particle.vx += dx * force * 0.001;
      particle.vy += dy * force * 0.001;
    }

    // パーティクル間の線
    particles.forEach((otherParticle, otherIndex) => {
      if (index !== otherIndex) {
        const dx = particle.x - otherParticle.x;
        const dy = particle.y - otherParticle.y;
        const distance = Math.sqrt(dx * dx + dy * dy);

        if (distance < 80) {
          ctx.save();
          ctx.globalAlpha = (80 - distance) / 80 * 0.2;
          ctx.strokeStyle = '#667eea';
          ctx.lineWidth = 1;
          ctx.beginPath();
          ctx.moveTo(particle.x, particle.y);
          ctx.lineTo(otherParticle.x, otherParticle.y);
          ctx.stroke();
          ctx.restore();
        }
      }
    });
  });

  requestAnimationFrame(animate);
}

animate();

// コンテンツのアニメーション
gsap.from('.particle-title', {
  duration: 1.5,
  y: 100,
  opacity: 0,
  ease: "power3.out"
});

gsap.from('.particle-subtitle', {
  duration: 1.5,
  y: 50,
  opacity: 0,
  ease: "power3.out",
  delay: 0.3
});

gsap.from('.particle-button', {
  duration: 1.5,
  y: 30,
  opacity: 0,
  scale: 0.8,
  ease: "back.out(1.7)",
  delay: 0.6
});

// ボタンクリック時のエフェクト
document.querySelector('.particle-button').addEventListener('click', () => {
  // パーティクルの爆発エフェクト
  particles.forEach(particle => {
    particle.vx *= 3;
    particle.vy *= 3;
    particle.size *= 1.5;
  });

  // 元に戻す
  setTimeout(() => {
    particles.forEach(particle => {
      particle.vx *= 0.3;
      particle.vy *= 0.3;
      particle.size *= 0.67;
    });
  }, 500);
});

実装時の注意点

パフォーマンス最適化

GSAPを使用する際は、以下の点に注意してパフォーマンスを最適化しましょう:

  1. GPU加速プロパティの優先使用: transformopacityscalerotationなどのGPU加速されるプロパティを優先的に使用します。lefttopwidthheightなどのレイアウトプロパティは避けましょう。
  2. will-changeプロパティの活用: アニメーション要素にwill-change: transformを追加することで、ブラウザの最適化を促進できます。
  3. 不要なアニメーションの停止: ページを離れる際や要素が非表示になった際は、gsap.killTweensOf()でアニメーションを停止し、メモリリークを防ぎます。

モバイル対応

モバイルデバイスでの快適な動作を確保するため:

  1. reduce-motionメディアクエリの尊重: ユーザーがアニメーションを無効にしている場合は、アニメーションを簡素化または無効化します。
  2. タッチイベントの対応: mouseenter/mouseleaveの代わりにtouchstart/touchendイベントも考慮しましょう。
  3. パフォーマンス監視: 特に複雑なアニメーションでは、フレームレートを監視して必要に応じて調整します。

まとめ

今回はGSAPを使った実用的なアニメーション8選をご紹介しました。

どれもコピペするだけで使えるので、プロジェクトのニーズに合わせて選んでみてください。初心者の方はフェードインから始めて、慣れてきたらScrollTriggerパララックス効果に挑戦することをおすすめします。

特にScrollTriggerを使ったアニメーションは、ユーザーエンゲージメントを大幅に向上させる効果があるため、ランディングページやポートフォリオサイトで積極的に活用していただければと思います。

GSAPの可能性は無限大です。これらの基本パターンをマスターしたら、ぜひオリジナルのアニメーションにも挑戦してみてください。

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次