はじめに
今回は、現場で愛用されている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を使用する際は、以下の点に注意してパフォーマンスを最適化しましょう:
- GPU加速プロパティの優先使用:
transform
、opacity
、scale
、rotation
などのGPU加速されるプロパティを優先的に使用します。left
、top
、width
、height
などのレイアウトプロパティは避けましょう。 - will-changeプロパティの活用: アニメーション要素に
will-change: transform
を追加することで、ブラウザの最適化を促進できます。 - 不要なアニメーションの停止: ページを離れる際や要素が非表示になった際は、
gsap.killTweensOf()
でアニメーションを停止し、メモリリークを防ぎます。
モバイル対応
モバイルデバイスでの快適な動作を確保するため:
- reduce-motionメディアクエリの尊重: ユーザーがアニメーションを無効にしている場合は、アニメーションを簡素化または無効化します。
- タッチイベントの対応:
mouseenter
/mouseleave
の代わりにtouchstart
/touchend
イベントも考慮しましょう。 - パフォーマンス監視: 特に複雑なアニメーションでは、フレームレートを監視して必要に応じて調整します。
まとめ
今回はGSAPを使った実用的なアニメーション8選をご紹介しました。
どれもコピペするだけで使えるので、プロジェクトのニーズに合わせて選んでみてください。初心者の方はフェードインから始めて、慣れてきたらScrollTriggerやパララックス効果に挑戦することをおすすめします。
特にScrollTriggerを使ったアニメーションは、ユーザーエンゲージメントを大幅に向上させる効果があるため、ランディングページやポートフォリオサイトで積極的に活用していただければと思います。
GSAPの可能性は無限大です。これらの基本パターンをマスターしたら、ぜひオリジナルのアニメーションにも挑戦してみてください。