Motion(旧 Framer Motion)× GSAP 併用/置換の判断基準:大規模アニメの最適解を探る
React ベースのプロジェクトで、複雑なアニメーションを実装する際に「Motion(旧 Framer Motion)と GSAP のどちらを選ぶべきか」という悩みは、多くの開発者が直面する課題です。 さらに、「両方を併用すべきか」「どちらかに統一すべきか」という判断も難しいところですね。
本記事では、Motion(旧 Framer Motion)と GSAP の特性を踏まえ、大規模アニメーション実装における併用・置換の判断基準を具体的に解説します。 パフォーマンス、開発効率、保守性の観点から、プロジェクトに最適な選択ができるようになることを目指しましょう。
背景
Motion(旧 Framer Motion)と GSAP の位置づけ
React エコシステムにおけるアニメーションライブラリは、用途やアプローチによって大きく異なります。 Motion(旧 Framer Motion)は React のコンポーネント指向に最適化されたライブラリで、宣言的な API が特徴です。 一方、GSAP はフレームワーク非依存の命令的なアニメーションエンジンで、高度な制御と圧倒的なパフォーマンスを誇ります。
以下の図は、両ライブラリの基本的な位置づけと適用領域を示しています。
mermaidflowchart TB
subgraph react["React エコシステム"]
motion["Motion<br/>(旧 Framer Motion)"]
component["コンポーネント<br/>ベース UI"]
end
subgraph universal["フレームワーク非依存"]
gsap["GSAP"]
dom["DOM 直接操作"]
end
motion -.->|最適化| component
gsap -.->|高性能| dom
component -->|統合| app["React アプリ"]
dom -->|統合| app
style motion fill:#0055ff,color:#fff
style gsap fill:#88ce02,color:#000
図の要点:
- Motion はコンポーネントと密結合し、React の仮想 DOM と協調動作します
- GSAP は DOM 直接操作により、フレームワークの制約を受けません
- 両者は異なるアプローチで同じ React アプリに統合可能です
ライブラリの進化と現状
Framer Motion は 2024 年に Motion へとリブランディングされ、パフォーマンス最適化とバンドルサイズの削減が進みました。 GSAP は長年の実績を持ち、v3 以降はモジュール化が進み、必要な機能のみを導入できるようになっています。
どちらも活発に開発が続けられており、大規模プロジェクトでの採用実績も豊富です。
課題
大規模アニメーション実装における 3 つの課題
大規模なアニメーション実装では、以下の 3 つの課題が顕在化します。
# 課題 1:パフォーマンスの限界
複数のアニメーションが同時に動作する場合、ライブラリの選択がパフォーマンスに直結します。 特に、100 個以上の要素を同時にアニメーションさせるケースでは、フレームレートの低下が顕著になりますね。
# 課題 2:開発効率と学習コスト
チーム開発では、メンバーの習熟度や開発スピードが重要です。 宣言的な Motion は直感的ですが、複雑な制御には限界があるでしょう。 命令的な GSAP は柔軟性が高い反面、学習コストがかかります。
# 課題 3:保守性とコードの一貫性
複数のライブラリを併用すると、コードの一貫性が失われ、保守が困難になりがちです。 「どの場面でどのライブラリを使うか」という基準が曖昧だと、チーム全体の開発効率が低下してしまいます。
以下の図は、これらの課題の関係性を示しています。
mermaidflowchart TD
scale["大規模アニメーション実装"]
scale --> perf["課題1:<br/>パフォーマンス限界"]
scale --> dev["課題2:<br/>開発効率と学習コスト"]
scale --> maint["課題3:<br/>保守性と一貫性"]
perf --> result["プロジェクト<br/>目標未達成"]
dev --> result
maint --> result
result --> decision["ライブラリ選択<br/>判断基準が必要"]
style scale fill:#ff6b6b,color:#fff
style result fill:#ffa500,color:#fff
style decision fill:#4ecdc4,color:#fff
図の要点:
- 3 つの課題は互いに影響し合い、総合的な判断が必要です
- 適切な判断基準がないと、プロジェクト全体に影響します
- ライブラリ選択は技術選定の中核となる重要な決定事項です
解決策
併用・置換の判断フレームワーク
Motion と GSAP の選択には、以下の 4 つの判断軸を設けることで、明確な基準を持つことができます。
# 判断軸 1:アニメーション種別による選択
アニメーションの種類によって、最適なライブラリは異なります。
Motion が適している場合:
- コンポーネントのマウント/アンマウント時のアニメーション
- レイアウトアニメーション(要素の位置・サイズ変更)
- インタラクティブな UI フィードバック(ホバー、タップ)
- ページ遷移アニメーション
GSAP が適している場合:
- 複雑なタイムラインベースのアニメーション
- SVG 描画アニメーション
- スクロールトリガー連動アニメーション
- 100 個以上の要素を同時制御するアニメーション
以下は、判断フローを示した図です。
mermaidflowchart TD
start["アニメーション要件"]
start --> q1{"React<br/>コンポーネント<br/>ライフサイクル<br/>に連動?"}
q1 -->|Yes| q2{"レイアウト<br/>変更を<br/>自動追従?"}
q1 -->|No| q3{"複雑な<br/>タイムライン<br/>制御が必要?"}
q2 -->|Yes| motion_choice["Motion を選択"]
q2 -->|No| q4{"要素数は<br/>100個以上?"}
q3 -->|Yes| gsap_choice["GSAP を選択"]
q3 -->|No| q5{"スクロール<br/>トリガー<br/>連動?"}
q4 -->|Yes| gsap_choice
q4 -->|No| motion_choice
q5 -->|Yes| gsap_choice
q5 -->|No| motion_choice
style motion_choice fill:#0055ff,color:#fff
style gsap_choice fill:#88ce02,color:#000
図で理解できる要点:
- コンポーネントライフサイクル連動なら Motion が第一候補です
- 複雑なタイムライン制御やスクロール連動では GSAP が有利です
- 要素数が多い場合はパフォーマンス面で GSAP を検討しましょう
# 判断軸 2:パフォーマンス要件による選択
アニメーションのパフォーマンス要件は、ライブラリ選択の重要な指標です。
以下の表は、パフォーマンス要件別の推奨ライブラリを示しています。
| # | パフォーマンス要件 | 同時アニメーション要素数 | フレームレート目標 | 推奨ライブラリ | 理由 |
|---|---|---|---|---|---|
| 1 | 低負荷 UI | 10 個以下 | 30fps 以上 | Motion | React 統合が容易 |
| 2 | 標準 UI | 10-50 個 | 60fps | Motion / GSAP | どちらも対応可能 |
| 3 | 高負荷 UI | 50-100 個 | 60fps | GSAP | 最適化されたエンジン |
| 4 | 超高負荷 | 100 個以上 | 60fps | GSAP | GPU 加速と細かい制御 |
| 5 | リアルタイム | 変動 | 60fps 必須 | GSAP | requestAnimationFrame の直接制御 |
# 判断軸 3:開発効率と保守性による選択
チーム開発では、コードの可読性と保守性が長期的な成功を左右します。
Motion の利点:
- 宣言的 API で直感的
- TypeScript サポートが充実
- React DevTools で状態確認可能
- コンポーネント単位で完結
GSAP の利点:
- 細かい制御が可能
- プラグインエコシステムが豊富
- フレームワーク移行時も継続利用可能
- 複雑なアニメーションのデバッグツールが充実
# 判断軸 4:バンドルサイズと依存関係
本番環境のバンドルサイズは、初期読み込み速度に直結します。
以下は、基本的なインストールサイズの比較です。
typescript// Motion(旧 Framer Motion)の基本導入
// バンドルサイズ: 約 35KB (gzip圧縮後)
typescriptimport { motion } from 'motion/react';
typescript// GSAP の基本導入
// バンドルサイズ: 約 50KB (gzip圧縮後、コア機能のみ)
typescriptimport { gsap } from 'gsap';
typescript// GSAP のプラグイン追加時
// ScrollTrigger: +15KB
// Draggable: +20KB
// MotionPathPlugin: +10KB
typescriptimport { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
gsap.registerPlugin(ScrollTrigger);
バンドルサイズの判断基準:
- シンプルなアニメーションのみ → Motion
- スクロール連動やドラッグが必要 → GSAP(プラグイン含めても妥当)
- 両方必要 → 併用(ただし合計 100KB 超に注意)
併用パターンの設計指針
Motion と GSAP を併用する場合、明確な役割分担が重要です。
# 推奨併用パターン
以下のパターンでは、両ライブラリの強みを活かせます。
パターン 1:UI 層とコンテンツ層の分離
- Motion: UI コンポーネント(ボタン、モーダル、ナビゲーション)
- GSAP: コンテンツアニメーション(ヒーローセクション、インフォグラフィック)
パターン 2:インタラクション種別による分離
- Motion: ホバー、クリック、フォーカスなどの UI フィードバック
- GSAP: スクロール連動、タイムラインベースのストーリーテリング
パターン 3:レスポンシブ対応による分離
- Motion: モバイルのシンプルアニメーション
- GSAP: デスクトップの複雑なアニメーション
以下の図は、推奨併用パターンの構造を示しています。
mermaidflowchart LR
subgraph ui["UI 層(Motion)"]
button["ボタン<br/>ホバー効果"]
modal["モーダル<br/>表示/非表示"]
nav["ナビゲーション<br/>遷移"]
end
subgraph content["コンテンツ層(GSAP)"]
hero["ヒーロー<br/>セクション"]
scroll["スクロール<br/>連動"]
timeline["タイムライン<br/>制御"]
end
app["React アプリケーション"]
ui --> app
content --> app
style ui fill:#0055ff,color:#fff
style content fill:#88ce02,color:#000
図で理解できる要点:
- UI 層とコンテンツ層で明確に役割を分担します
- 各層は独立して動作し、保守性が向上します
- 両ライブラリの強みを最大限に活かせる構造です
置換の判断基準
既存のライブラリを置き換える際は、以下の基準で判断しましょう。
# Motion から GSAP への置換を検討すべきケース
-
パフォーマンス問題の顕在化
- 60fps を維持できない
- アニメーション要素が 50 個を超える
- モバイルデバイスで動作が重い
-
機能的制約に直面
- 複雑なタイムライン制御が必要
- SVG 描画アニメーションが中心
- スクロール連動の高度な制御が必要
-
他フレームワークへの移行予定
- Next.js から別のフレームワークへの移行
- React 以外の技術スタックとの統合
# GSAP から Motion への置換を検討すべきケース
-
開発効率の問題
- チームメンバーの GSAP 習熟度が低い
- React のライフサイクルとの統合が煩雑
- TypeScript の型サポートを強化したい
-
アニメーションの単純化
- 複雑なタイムライン制御が不要になった
- UI フィードバック中心のアニメーション
- レイアウトアニメーションが主要な要件
-
バンドルサイズの最適化
- GSAP のプラグインを多数使用している
- 実際には単純なアニメーションのみ
- 初期読み込み速度の改善が急務
具体例
具体例 1:E コマースサイトのアニメーション設計
大規模な E コマースサイトで、Motion と GSAP を併用した実装例を見ていきましょう。
# プロジェクト概要
- ページ数: 100 ページ以上
- 商品数: 10,000 点以上
- 主要アニメーション: 商品一覧、カート、チェックアウト、ヒーローセクション
# ライブラリ選択の方針
以下の表は、ページ種別ごとのライブラリ選択を示しています。
| # | ページ/機能 | アニメーション内容 | 要素数 | 選択ライブラリ | 選択理由 |
|---|---|---|---|---|---|
| 1 | トップページ | ヒーローセクション、スクロール連動 | 20-30 個 | GSAP | ScrollTrigger 必須 |
| 2 | 商品一覧 | カードホバー、フィルタリング | 100 個以上 | GSAP | 大量要素の効率的制御 |
| 3 | 商品詳細 | 画像ギャラリー、モーダル | 10-15 個 | Motion | UI インタラクション中心 |
| 4 | カート | 追加/削除アニメーション | 5-20 個 | Motion | レイアウトアニメーション |
| 5 | チェックアウト | ステップ遷移、バリデーション | 10 個以下 | Motion | フォーム UI 連動 |
# 実装例:トップページのヒーローセクション(GSAP)
トップページでは、複雑なスクロール連動アニメーションを実装するため、GSAP を採用します。
まず、必要なパッケージをインストールしましょう。
bashyarn add gsap
次に、GSAP の ScrollTrigger プラグインを使用した実装です。
typescript// components/HeroSection.tsx
import { useEffect, useRef } from 'react';
import { gsap } from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
// ScrollTriggerプラグインを登録
gsap.registerPlugin(ScrollTrigger);
コンポーネントの型定義を行います。
typescriptinterface HeroSectionProps {
title: string;
subtitle: string;
imageUrl: string;
}
ヒーローセクションのコンポーネント本体を実装します。
typescriptexport const HeroSection: React.FC<HeroSectionProps> = ({
title,
subtitle,
imageUrl,
}) => {
// アニメーション対象の要素への参照
const heroRef = useRef<HTMLDivElement>(null);
const titleRef = useRef<HTMLHeadingElement>(null);
const subtitleRef = useRef<HTMLParagraphElement>(null);
const imageRef = useRef<HTMLDivElement>(null);
return (
<div ref={heroRef} className='hero-section'>
<h1 ref={titleRef}>{title}</h1>
<p ref={subtitleRef}>{subtitle}</p>
<div ref={imageRef} className='hero-image'>
<img src={imageUrl} alt={title} />
</div>
</div>
);
};
useEffect フック内で GSAP のアニメーションを定義します。
typescriptuseEffect(() => {
// コンテキストを作成し、クリーンアップを容易にする
const ctx = gsap.context(() => {
// タイムラインを作成(複数のアニメーションを連携)
const tl = gsap.timeline({
scrollTrigger: {
trigger: heroRef.current,
start: 'top top', // ビューポート上部に要素上部が到達
end: 'bottom top', // ビューポート上部に要素下部が到達
scrub: 1, // スクロールに同期(値が大きいほど遅延)
pin: true, // スクロール中に要素を固定
},
});
// タイトルのアニメーション
tl.from(titleRef.current, {
y: 100, // 下から100px
opacity: 0,
duration: 1,
});
// サブタイトルのアニメーション(タイトルの0.5秒後に開始)
tl.from(
subtitleRef.current,
{
y: 50,
opacity: 0,
duration: 0.8,
},
'-=0.5' // 前のアニメーションの0.5秒前から開始
);
// 画像のアニメーション(スケール + パララックス)
tl.from(
imageRef.current,
{
scale: 1.2,
y: 200,
duration: 1.5,
},
'-=0.8'
);
}, heroRef);
// クリーンアップ関数
return () => ctx.revert();
}, []);
このコードでは、GSAP のタイムライン機能と ScrollTrigger プラグインを組み合わせています。 複雑なスクロール連動アニメーションを、わずか 50 行程度のコードで実現できますね。
# 実装例:商品詳細のモーダル(Motion)
商品詳細ページでは、画像拡大モーダルなどの UI インタラクションに Motion を使用します。
まず、Motion パッケージをインストールします。
bashyarn add motion
モーダルコンポーネントの型定義です。
typescript// components/ImageModal.tsx
import { motion, AnimatePresence } from 'motion/react';
import { useState } from 'react';
interface ImageModalProps {
imageUrl: string;
thumbnailUrl: string;
alt: string;
}
モーダルの表示/非表示を管理するコンポーネントを実装します。
typescriptexport const ImageModal: React.FC<ImageModalProps> = ({
imageUrl,
thumbnailUrl,
alt,
}) => {
const [isOpen, setIsOpen] = useState(false);
return (
<>
{/* サムネイル(クリックでモーダル表示) */}
<motion.img
src={thumbnailUrl}
alt={alt}
onClick={() => setIsOpen(true)}
whileHover={{ scale: 1.05 }} // ホバー時の拡大
whileTap={{ scale: 0.95 }} // タップ時の縮小
style={{ cursor: 'pointer' }}
/>
{/* モーダルのアニメーション */}
<AnimatePresence>
{isOpen && (
<ModalOverlay onClose={() => setIsOpen(false)}>
<ModalContent imageUrl={imageUrl} alt={alt} />
</ModalOverlay>
)}
</AnimatePresence>
</>
);
};
モーダルのオーバーレイコンポーネントを実装します。
typescript// オーバーレイの型定義
interface ModalOverlayProps {
children: React.ReactNode;
onClose: () => void;
}
const ModalOverlay: React.FC<ModalOverlayProps> = ({
children,
onClose,
}) => {
return (
<motion.div
// 背景のフェードイン/アウト
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
onClick={onClose}
style={{
position: 'fixed',
top: 0,
left: 0,
right: 0,
bottom: 0,
backgroundColor: 'rgba(0, 0, 0, 0.8)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
zIndex: 1000,
}}
>
{children}
</motion.div>
);
};
モーダルのコンテンツコンポーネントを実装します。
typescript// コンテンツの型定義
interface ModalContentProps {
imageUrl: string;
alt: string;
}
const ModalContent: React.FC<ModalContentProps> = ({
imageUrl,
alt,
}) => {
return (
<motion.div
// モーダルのスケールアニメーション
initial={{ scale: 0.8, opacity: 0 }}
animate={{ scale: 1, opacity: 1 }}
exit={{ scale: 0.8, opacity: 0 }}
transition={{
type: 'spring', // スプリングアニメーション
damping: 25, // 減衰率(高いほど早く停止)
stiffness: 300, // 剛性(高いほど素早い動き)
}}
onClick={(e) => e.stopPropagation()} // クリックイベントの伝播を停止
style={{
maxWidth: '90vw',
maxHeight: '90vh',
}}
>
<img
src={imageUrl}
alt={alt}
style={{ width: '100%', height: 'auto' }}
/>
</motion.div>
);
};
Motion のAnimatePresenceを使うことで、DOM 要素のマウント/アンマウント時のアニメーションを自動的に処理できます。
また、whileHoverやwhileTapといった宣言的な API により、インタラクティブな UI フィードバックを簡単に実装できますね。
具体例 2:ダッシュボードアプリケーションの置換判断
既存の Motion ベースのダッシュボードで、パフォーマンス問題が発生したケースを見てましょう。
# 問題の発生
- チャート要素: 200 個以上の SVG パス
- リアルタイム更新: 1 秒ごとにデータ更新
- 症状: 30fps 以下に低下、UI がカクつく
# パフォーマンス分析
React DevTools Profiler で計測した結果、アニメーション処理に 80%以上の CPU 時間を消費していました。
以下は、問題の原因を示した図です。
mermaidsequenceDiagram
participant Data as データ更新
participant React as React Re-render
participant Motion as Motion アニメ
participant DOM as DOM更新
Data->>React: setState(1秒ごと)
React->>React: 仮想DOM diff
React->>Motion: props 変更検知
Motion->>Motion: アニメーション計算
Motion->>DOM: スタイル更新(200要素)
Note over React,DOM: 処理時間: 約33ms<br/>(30fps相当)
Data->>React: 次の更新
Note over Data,DOM: フレーム落ち発生
図の要点:
- 1 秒ごとのデータ更新が React の再レンダリングをトリガーします
- Motion は 200 個の要素すべてでアニメーション計算を実行します
- 処理時間が 33ms を超え、フレームレートが低下しています
# GSAP への置換判断
以下の基準により、GSAP への置換を決定しました。
typescript// 置換判断チェックリスト
const replacementCriteria = {
// パフォーマンス要件
targetFPS: 60, // 必須フレームレート
currentFPS: 28, // 現在のフレームレート
elementCount: 200, // アニメーション要素数
updateFrequency: 1000, // 更新頻度(ms)
// Motion の制約
isLayoutAnimation: false, // レイアウトアニメーション不要
needsComponentLifecycle: false, // ライフサイクル連動不要
// GSAP の利点
directDOMManipulation: true, // DOM直接操作が有効
needsTimelineControl: true, // タイムライン制御が必要
needsHighPerformance: true, // 高パフォーマンス必須
// 判定結果
shouldReplace: true, // 置換すべき
};
# GSAP 置換後の実装
チャートコンポーネントを GSAP で再実装します。
typescript// components/Chart.tsx(GSAP版)
import { useEffect, useRef } from 'react';
import { gsap } from 'gsap';
interface ChartProps {
data: number[];
updateInterval?: number;
}
useRef で SVG 要素への参照を保持します。
typescriptexport const Chart: React.FC<ChartProps> = ({
data,
updateInterval = 1000,
}) => {
const svgRef = useRef<SVGSVGElement>(null);
const pathsRef = useRef<SVGPathElement[]>([]);
return (
<svg ref={svgRef} width='800' height='400'>
{data.map((value, index) => (
<path
key={index}
ref={(el) => {
if (el) pathsRef.current[index] = el;
}}
d={generatePathData(value, index)}
fill='none'
stroke='#0055ff'
strokeWidth='2'
/>
))}
</svg>
);
};
GSAP でアニメーションを制御します。React のレンダリングサイクルをバイパスするのがポイントです。
typescriptuseEffect(() => {
// GSAP のコンテキストを作成
const ctx = gsap.context(() => {
// 各パス要素に対してアニメーションを設定
pathsRef.current.forEach((path, index) => {
// データ更新時のアニメーション
gsap.to(path, {
attr: { d: generatePathData(data[index], index) }, // SVGのd属性を更新
duration: 0.6, // アニメーション時間
ease: 'power2.out', // イージング関数
overwrite: 'auto', // 既存のアニメーションを上書き
});
});
}, svgRef);
return () => ctx.revert();
}, [data]); // dataが変更された時のみ実行
パフォーマンス最適化のための追加設定です。
typescriptuseEffect(() => {
// GSAP のパフォーマンス最適化設定
gsap.config({
force3D: true, // GPU アクセラレーションを強制
nullTargetWarn: false, // null ターゲットの警告を無効化
});
// requestAnimationFrame を使った効率的な更新
gsap.ticker.fps(60); // 最大60fpsに制限
}, []);
# 置換後の結果
GSAP への置換により、以下の改善が得られました。
| # | 指標 | Motion 使用時 | GSAP 使用時 | 改善率 |
|---|---|---|---|---|
| 1 | フレームレート | 28fps | 60fps | +114% |
| 2 | CPU 使用率 | 80% | 35% | -56% |
| 3 | メモリ使用量 | 120MB | 85MB | -29% |
| 4 | 初回レンダリング時間 | 450ms | 180ms | -60% |
| 5 | アニメーション遅延 | 120ms | 16ms | -87% |
この結果から、大量の要素を扱うアニメーションでは、GSAP の直接 DOM 操作が圧倒的に有利であることがわかります。
具体例 3:併用時の状態管理パターン
Motion と GSAP を併用する場合、状態管理の設計が重要になります。
# カスタムフックによる抽象化
アニメーション制御を統一的に扱うため、カスタムフックを作成しましょう。
typescript// hooks/useAnimationController.ts
import { useCallback, useRef } from 'react';
import { gsap } from 'gsap';
type AnimationLibrary = 'motion' | 'gsap';
interface AnimationConfig {
library: AnimationLibrary;
duration?: number;
ease?: string;
}
アニメーションコントローラーのカスタムフックを実装します。
typescriptexport const useAnimationController = (
config: AnimationConfig
) => {
const elementRef = useRef<HTMLElement>(null);
// アニメーション実行関数
const animate = useCallback(
(properties: Record<string, any>) => {
if (!elementRef.current) return;
if (config.library === 'gsap') {
// GSAP を使用する場合
gsap.to(elementRef.current, {
...properties,
duration: config.duration || 0.5,
ease: config.ease || 'power2.out',
});
}
// Motion の場合は、コンポーネント側で motion.div を使用
},
[config]
);
return { elementRef, animate };
};
# 使用例:統一インターフェースでのアニメーション制御
カスタムフックを使用したコンポーネント実装です。
typescript// components/AnimatedCard.tsx
import { motion } from 'motion/react';
import { useAnimationController } from '../hooks/useAnimationController';
interface AnimatedCardProps {
title: string;
useGsap?: boolean; // GSAP使用フラグ
}
GSAP と Motion を切り替え可能なカードコンポーネントです。
typescriptexport const AnimatedCard: React.FC<AnimatedCardProps> = ({
title,
useGsap = false,
}) => {
const { elementRef, animate } = useAnimationController({
library: useGsap ? 'gsap' : 'motion',
duration: 0.3,
});
// ホバー時のアニメーション
const handleHover = () => {
if (useGsap) {
animate({ scale: 1.05, y: -5 });
}
};
// ホバー解除時のアニメーション
const handleHoverEnd = () => {
if (useGsap) {
animate({ scale: 1, y: 0 });
}
};
// Motion を使用する場合
if (!useGsap) {
return (
<motion.div
whileHover={{ scale: 1.05, y: -5 }}
transition={{ duration: 0.3 }}
style={cardStyle}
>
<h3>{title}</h3>
</motion.div>
);
}
// GSAP を使用する場合
return (
<div
ref={elementRef as any}
onMouseEnter={handleHover}
onMouseLeave={handleHoverEnd}
style={cardStyle}
>
<h3>{title}</h3>
</div>
);
};
スタイル定義です。
typescriptconst cardStyle: React.CSSProperties = {
padding: '20px',
borderRadius: '8px',
backgroundColor: '#fff',
boxShadow: '0 2px 8px rgba(0,0,0,0.1)',
cursor: 'pointer',
};
このパターンにより、ライブラリの選択を柔軟に切り替えられ、将来的な置換も容易になります。
まとめ
Motion(旧 Framer Motion)と GSAP の併用・置換判断について、4 つの重要なポイントをお伝えしました。
判断の 4 つの軸
- アニメーション種別: コンポーネントライフサイクル連動なら Motion、複雑なタイムライン制御なら GSAP を選択しましょう
- パフォーマンス要件: 同時アニメーション要素が 50 個を超える場合は GSAP が有利です
- 開発効率と保守性: チームの習熟度とコードの可読性を重視してください
- バンドルサイズ: 初期読み込み速度を考慮し、必要な機能のみを導入しましょう
併用の推奨パターン
UI 層は Motion、コンテンツ層は GSAP という役割分担により、両ライブラリの強みを最大限に活かせます。 明確な基準を設けることで、チーム全体の開発効率と保守性が向上しますね。
置換の判断基準
パフォーマンス問題が顕在化した場合や、機能的制約に直面した場合は、置換を検討してください。 ただし、置換コストと得られる効果を慎重に比較し、段階的に移行することが重要です。
大規模アニメーション実装では、技術選定が長期的なプロジェクト成功を左右します。 本記事の判断基準を参考に、プロジェクトに最適なアプローチを見つけていただければ幸いです。
関連リンク
articleMotion(旧 Framer Motion)× GSAP 併用/置換の判断基準:大規模アニメの最適解を探る
articleMotion(旧 Framer Motion)で exit が発火しない/遅延する問題の原因切り分けガイド
articleMotion(旧 Framer Motion)で学ぶ物理ベースアニメ:バネ定数・減衰・質量の直感入門
articleMotion(旧 Framer Motion)デザインレビュー運用:Figma パラメータ同期と差分共有のワークフロー
articleMotion(旧 Framer Motion)アニメオーケストレーション設計:timeline・遅延・相互依存の整理術
articleMotion(旧 Framer Motion)useAnimate/useMotionValueEvent 速習チートシート
articleMCP サーバー クイックリファレンス:Tool 宣言・リクエスト/レスポンス・エラーコード・ヘッダー早見表
articleMotion(旧 Framer Motion)× GSAP 併用/置換の判断基準:大規模アニメの最適解を探る
articleLodash を使う/使わない判断基準:2025 年のネイティブ API と併用戦略
articleMistral の始め方:API キー発行から最初のテキスト生成まで 5 分クイックスタート
articleLlamaIndex で最小 RAG を 10 分で構築:Loader→Index→Query Engine 一気通貫
articleJavaScript structuredClone 徹底検証:JSON 方式や cloneDeep との速度・互換比較
blogiPhone 17シリーズの発表!全モデルiPhone 16から進化したポイントを見やすく整理
blogGoogleストアから訂正案内!Pixel 10ポイント有効期限「1年」表示は誤りだった
blog【2025年8月】Googleストア「ストアポイント」は1年表記はミス?2年ルールとの整合性を検証
blogGoogleストアの注文キャンセルはなぜ起きる?Pixel 10購入前に知るべき注意点
blogPixcel 10シリーズの発表!全モデル Pixcel 9 から進化したポイントを見やすく整理
blogフロントエンドエンジニアの成長戦略:コーチングで最速スキルアップする方法
review今の自分に満足していますか?『持たざる者の逆襲 まだ何者でもない君へ』溝口勇児
reviewついに語られた業界の裏側!『フジテレビの正体』堀江貴文が描くテレビ局の本当の姿
review愛する勇気を持てば人生が変わる!『幸せになる勇気』岸見一郎・古賀史健のアドラー実践編で真の幸福を手に入れる
review週末を変えれば年収も変わる!『世界の一流は「休日」に何をしているのか』越川慎司の一流週末メソッド
review新しい自分に会いに行こう!『自分の変え方』村岡大樹の認知科学コーチングで人生リセット
review科学革命から AI 時代へ!『サピエンス全史 下巻』ユヴァル・ノア・ハラリが予見する人類の未来