Framer Motion 完全ガイド - React向け高性能アニメーションライブラリ

Framer Motion 完全ガイド - React向け高性能アニメーションライブラリ

作成日:

Framer Motionとは

Framer Motionは、React向けのプロダクションレディなアニメーションライブラリです。シンプルなAPIで複雑なアニメーションを実現でき、パフォーマンスも優れています。

もともとはデザインツール「Framer」の内部で使用されていたアニメーションエンジンをオープンソース化したもので、実績のある信頼性の高いライブラリです。CSSアニメーションやJavaScriptのrequestAnimationFrameを直接扱う必要がなく、Reactの考え方(宣言的UI)に沿った形でアニメーションを記述できるのが最大の特徴です。

他のアニメーションライブラリとの比較

ライブラリ特徴向いている用途
Framer Motion宣言的API、React専用、豊富な機能React SPA、複雑なUI
GSAP高性能、細かい制御、学習コスト高めゲーム、広告、高度なアニメーション
Anime.js軽量、シンプル、フレームワーク非依存シンプルなアニメーション
React Spring物理ベース、Framer Motionに似ている自然な動きが必要な場面

特徴

  • 宣言的なAPI: animateinitialexitなどのpropsでアニメーションを定義。命令的なコードを書く必要がない
  • ジェスチャー対応: whileHoverwhileTapwhileDragで直感的なインタラクションを簡単に実装
  • バリアント: 複数のアニメーション状態を定義し、親子間で自動的に伝播。複雑な連動アニメーションも簡潔に書ける
  • レイアウトアニメーション: CSSの変更を自動検出してスムーズにアニメーション。手動でのサイズ計算が不要
  • AnimatePresence: DOM要素の削除時にexitアニメーションを実行。React標準では難しい「消える」演出が簡単
  • Springアニメーション: 物理ベースの自然な動き。イージング関数を考える必要がなく、直感的なパラメータで調整可能

インストール

Framer Motionは単一パッケージで提供されており、追加の依存関係は不要です。

Shell
npm install framer-motion

注意点:

  • React 18以上が必要です
  • Next.js App Routerで使用する場合、アニメーションを使うコンポーネントには 'use client' ディレクティブが必要です
  • SSRと互換性があり、サーバーサイドでも安全に動作します

基本的な使い方

Framer Motionの基本は非常にシンプルです。通常のHTML要素を motion. プレフィックス付きのコンポーネントに置き換えるだけで、アニメーション機能が有効になります。

motion.divコンポーネント

motion.divmotion.spanmotion.buttonなど、すべての標準HTMLタグに対応するmotionコンポーネントが用意されています。これらは通常のHTMLタグと同じように使用でき、追加のpropsでアニメーションを定義します。

TypeScript
import { motion } from 'framer-motion';
 
function App() {
  return (
    <motion.div
      initial={{ opacity: 0, scale: 0.5 }}
      animate={{ opacity: 1, scale: 1 }}
      transition={{ duration: 0.5 }}
    >
      Hello Framer Motion!
    </motion.div>
  );
}

主要なprops

Props説明
initialアニメーション開始時(マウント時)の状態{{ opacity: 0, y: 20 }}
animateアニメーション終了時(目標)の状態{{ opacity: 1, y: 0 }}
transitionアニメーションの設定(時間、イージング、タイプなど){{ duration: 0.5, ease: 'easeOut' }}
exitアンマウント時の状態(AnimatePresenceと併用){{ opacity: 0, scale: 0.8 }}

Framer Motionは initialanimate の差分を自動的に計算し、スムーズな補間を行います。transition を省略した場合は、デフォルトでSpringアニメーションが適用されます。

基本的なアニメーション

初期表示アニメーション

無限回転

クリックでアニメーション

<motion.div initial={{ opacity: 0, scale: 0.5 }} animate={{ opacity: 1, scale: 1 }} transition={{ duration: 0.8 }} />

上のデモでは、ページ読み込み時にフェードイン・スケールアップする要素、無限回転する要素、クリックでアニメーションが再生される要素を確認できます。

ホバー・タップアニメーション

ユーザーインタラクションに対する視覚的フィードバックは、UIの品質を大きく左右します。Framer Motionでは、whileHoverwhileTapを使用して、CSSの:hover疑似クラスでは実現しにくい滑らかなアニメーションを簡単に実装できます。

特にボタンやカードなどのインタラクティブ要素に適用すると、クリック可能であることを直感的に伝え、操作した際の満足感を高めることができます。

TypeScript
<motion.button
  whileHover={{ scale: 1.1 }}
  whileTap={{ scale: 0.95 }}
  transition={{ type: 'spring', stiffness: 400, damping: 17 }}
>
  クリック!
</motion.button>

ホバー・タップアニメーション

ホバー: 拡大 + 回転

ホバー: グラデーション変化

Springアニメーション

<motion.button whileHover={{ scale: 1.05 }} whileTap={{ scale: 0.95 }} transition={{ type: "spring", stiffness: 400 }} />

上のデモでは、ホバー時の拡大・回転、グラデーション変化、そしてSpringアニメーションを使ったボタンの押し込み効果を確認できます。

使用可能なジェスチャーprops

Props説明使用例
whileHoverホバー中のアニメーションボタン、カード、リンクのフィードバック
whileTapクリック/タップ中のアニメーションボタンの押し込み効果
whileFocusフォーカス中のアニメーションフォーム入力フィールドのハイライト
whileDragドラッグ中のアニメーションドラッグ可能要素の視覚的強調
whileInViewビューポート内に入った時のアニメーションスクロールで表示されるコンテンツ

ポイント: whileHoverwhileTapを組み合わせることで、ホバー時に拡大、タップ時に縮小という自然な押しボタンの動きを表現できます。

トランジション設定

transitionプロパティは、アニメーションの**「どのように動くか」**を制御します。Framer Motionでは、主に2種類のアニメーションタイプが用意されています。


Springアニメーション

Springアニメーションは、Framer Motionのデフォルトのアニメーションタイプです。物理ベースのバネシミュレーションにより、自然で心地よい動きを実現します。

従来のイージング関数(ease-in-outなど)とは異なり、終了時間を指定するのではなく、バネの物理特性を指定します。これにより、速度に応じた自然な減速や、跳ね返りの動きを表現できます。

TypeScript
<motion.div
  animate={{ x: 100 }}
  transition={{
    type: 'spring',
    stiffness: 500,  // バネの硬さ(高いほど速く動く)
    damping: 15,     // 減衰(低いほど跳ねる)
    mass: 1          // 質量(高いほど重く動く)
  }}
/>

Springパラメータの詳細

パラメータ説明低い値高い値
stiffnessバネの硬さゆっくり、柔らかい動き速い、キビキビした動き
damping減衰(抵抗)跳ね返りが多いすぐに止まる
mass質量軽い、素早く動く重い、ゆっくり動く
velocity初速度-アニメーション開始時の速度を指定

スプリングアニメーション設定

🎾

Bouncy

stiffness: 500
damping: 15

🎾

Smooth

stiffness: 100
damping: 20

🎾

Stiff

stiffness: 700
damping: 30

🎾

Gentle

stiffness: 50
damping: 10

※ 各ボールをクリックするとスプリングの違いを確認できます

stiffness: バネの硬さ(高いほど速く動く)

damping: 減衰(低いほど跳ねる)

mass: 質量(高いほど重く動く)

transition={{ type: "spring", stiffness: 500, // バネの硬さ damping: 15, // 減衰 mass: 1 // 質量 }}

上のデモで各ボールをクリックすると、stiffnessとdampingの組み合わせによる動きの違いを確認できます。


Tweenアニメーション

従来のキーフレームベースのアニメーションです。正確な時間制御が必要な場合や、無限ループするアニメーションに適しています。

TypeScript
<motion.div
  animate={{ rotate: 360 }}
  transition={{
    type: 'tween',
    duration: 2,
    ease: 'easeInOut',
    repeat: Infinity
  }}
/>

主なイージング関数

イージング説明使用例
linear一定速度ローディングスピナー、進行バー
easeInゆっくり開始退場アニメーション
easeOutゆっくり終了登場アニメーション
easeInOutゆっくり開始・終了往復アニメーション
circIn/Out円形カーブより顕著な加減速
backIn/Out少し戻る動き強調したい動き
anticipate予備動作付き投げる、ジャンプなどの動き

Spring vs Tween の使い分け:

  • Spring: ユーザー操作への反応、自然な動きが欲しい時
  • Tween: 正確な時間制御、無限ループ、シーケンシャルなアニメーション

バリアント(Variants)

バリアントは、アニメーション状態に名前を付けて再利用可能にする仕組みです。複数の要素で同じアニメーションパターンを使いたい場合や、親子間でアニメーションを連動させたい場合に非常に便利です。

バリアントのメリット

  1. コードの再利用: 同じアニメーション定義を複数の要素で共有
  2. 親子連動: 親要素のアニメーション状態が自動的に子要素に伝播
  3. オーケストレーション: staggerChildrendelayChildrenで子要素のタイミングを制御
  4. 可読性向上: アニメーションロジックをコンポーネントから分離
TypeScript
const containerVariants = {
  hidden: { opacity: 0 },
  visible: {
    opacity: 1,
    transition: {
      staggerChildren: 0.1,  // 子要素を0.1秒ずつずらして表示
      delayChildren: 0.2     // 子要素のアニメーション開始を遅延
    }
  }
};
 
const itemVariants = {
  hidden: { opacity: 0, y: 20 },
  visible: { opacity: 1, y: 0 }
};
 
function List() {
  return (
    <motion.ul
      variants={containerVariants}
      initial="hidden"
      animate="visible"
    >
      {items.map(item => (
        <motion.li key={item} variants={itemVariants}>
          {item}
        </motion.li>
      ))}
    </motion.ul>
  );
}

バリアント & スタッガーアニメーション

🎨
🚀
💫
🎯
const containerVariants = { hidden: { opacity: 0 }, visible: { opacity: 1, transition: { staggerChildren: 0.1 } } }; <motion.div variants={containerVariants} initial="hidden" animate="visible"> {items.map(item => <motion.div variants={itemVariants} />)} </motion.div>

上のデモでは、ボタンをクリックすると複数のアイコンが順番にアニメーションします。これがstaggerChildrenの効果です。

staggerChildrenの効果

staggerChildrenを使用すると、子要素のアニメーションを順番に少しずつずらして実行できます。リストやグリッドの表示に最適で、「ドミノ倒し」のような連鎖的なアニメーションを簡単に実現できます。

オーケストレーションオプション

オプション説明
staggerChildren子要素間のアニメーション開始の遅延0.1(0.1秒ずつずらす)
delayChildren子要素全体のアニメーション開始遅延0.3(親から0.3秒後に開始)
staggerDirectionスタッガーの方向1(順方向), -1(逆方向)
when親子のアニメーション順序"beforeChildren", "afterChildren"

AnimatePresence - 出入りアニメーション

Reactの標準的な条件付きレンダリングでは、要素がアンマウントされると即座にDOMから削除されます。これは、「消える」アニメーションを実装する上で大きな障壁となります。

AnimatePresenceコンポーネントを使用すると、要素がDOMから削除される前にexitアニメーションを実行できます。これにより、モーダルのフェードアウト、リスト項目の削除アニメーション、ページトランジションなど、多くのUI演出が可能になります。

なぜAnimatePresenceが必要なのか

TypeScript
// これだけでは「消える」アニメーションは実行されない
{isVisible && <motion.div animate={{ opacity: 1 }} />}
// isVisibleがfalseになると即座に消える

AnimatePresenceで囲むことで、exitアニメーションが完了するまでDOM要素が保持されます。

TypeScript
import { motion, AnimatePresence } from 'framer-motion';
 
function Modal({ isOpen }) {
  return (
    <AnimatePresence>
      {isOpen && (
        <motion.div
          initial={{ opacity: 0, scale: 0.8 }}
          animate={{ opacity: 1, scale: 1 }}
          exit={{ opacity: 0, scale: 0.8 }}
          transition={{ type: 'spring' }}
        >
          モーダルコンテンツ
        </motion.div>
      )}
    </AnimatePresence>
  );
}

AnimatePresence - 出入りアニメーション

1
2
3

※ 要素をクリックすると削除されます

<AnimatePresence mode="popLayout"> {items.map(item => ( <motion.div key={item} initial={{ opacity: 0, scale: 0 }} animate={{ opacity: 1, scale: 1 }} exit={{ opacity: 0, scale: 0 }} /> ))} </AnimatePresence>

上のデモでは、「+ 追加」ボタンで要素を追加し、各要素をクリックすると削除されます。削除時にスケールダウンしながらフェードアウトするのがexitアニメーションの効果です。

AnimatePresenceのmode

mode説明使用例
sync(デフォルト)新旧要素が同時にアニメーション一般的なリスト操作
wait古い要素のexitが完了してから新しい要素がenterページトランジション、ステップウィザード
popLayout削除される要素がレイアウトから「ポップ」され、他の要素がスムーズに移動リスト項目の削除

重要なポイント

  • keyプロパティ: AnimatePresenceの直下の要素には必ず一意のkeyを設定してください。Reactがどの要素が追加/削除されたかを判断するために必要です。
  • initial=: 初回マウント時のアニメーションを無効にしたい場合に使用します(アコーディオンなど)。

スクロール連動アニメーション

スクロール連動アニメーションは、ユーザーのスクロール操作に応じて要素が変化する演出です。パララックス効果、プログレスバー、スクロールで現れるコンテンツなど、モダンなWebサイトでよく見られる表現を実現できます。

Framer MotionのuseScrolluseTransformフックを使用すると、スクロール位置を監視し、その値を別の値(opacity、scale、positionなど)に変換してアニメーションに適用できます。

useScrollとuseTransformの関係

  1. useScroll: スクロール位置を0〜1の値(progress)として取得
  2. useTransform: progressを別の値(opacity, x, scaleなど)にマッピング
  3. styleに適用: マッピングされた値をmotion要素のstyleに渡す
TypeScript
import { motion, useScroll, useTransform } from 'framer-motion';
import { useRef } from 'react';
 
function ScrollAnimation() {
  const ref = useRef(null);
  const { scrollYProgress } = useScroll({
    target: ref,
    offset: ['start end', 'end start']
  });
 
  // scrollYProgress: 0 → 0.5 → 1 を
  // opacity: 0 → 1 → 0 にマッピング
  const opacity = useTransform(scrollYProgress, [0, 0.5, 1], [0, 1, 0]);
  const scale = useTransform(scrollYProgress, [0, 0.5, 1], [0.8, 1, 0.8]);
 
  return (
    <motion.div ref={ref} style={{ opacity, scale }}>
      スクロールで変化
    </motion.div>
  );
}

スクロール連動アニメーション

※ ページをスクロールすると変化します

Opacity
& Scale
X移動
回転

スクロール進捗:

const { scrollYProgress } = useScroll({ target: ref }); const opacity = useTransform(scrollYProgress, [0, 0.5, 1], [0, 1, 0]); <motion.div style={{ opacity }} />

上のデモでは、ページをスクロールすると3つの要素がそれぞれ異なる方法でアニメーションします。スクロール進捗バーもuseScrollで実装されています。

useScrollのオプション

TypeScript
const { scrollYProgress } = useScroll({
  target: ref,                         // 監視する要素
  offset: ['start end', 'end start'],  // トリガー位置
  container: containerRef              // スクロールコンテナ(省略時はウィンドウ)
});

offsetの指定方法

offset['要素の位置 ビューポートの位置', '要素の位置 ビューポートの位置']の形式で指定します。

指定意味
'start end'要素の上端がビューポートの下端に達した時(要素が見え始める)
'center center'要素の中央がビューポートの中央に達した時
'end start'要素の下端がビューポートの上端に達した時(要素が見えなくなる)

パフォーマンスのポイント: useScrolluseTransformはReactの再レンダリングを発生させずにアニメーションを更新するため、非常に高いパフォーマンスを実現しています。

ドラッグ機能

Framer Motionは、ドラッグ&ドロップ機能を驚くほど簡単に実装できます。dragpropを追加するだけで、要素をマウスやタッチでドラッグ可能にできます。

ドラッグ機能は、カルーセル、スライダー、並べ替え可能なリスト、スワイプで削除するUI、インタラクティブなチュートリアルなど、様々な場面で活用できます。

基本的な使い方

TypeScript
<motion.div
  drag                                    // ドラッグを有効化
  dragConstraints={{ left: 0, right: 300, top: 0, bottom: 200 }}  // 移動範囲
  dragElastic={0.1}                       // 範囲外でのバウンド量
  dragMomentum={true}                     // 慣性
  whileDrag={{ scale: 1.1 }}              // ドラッグ中のスタイル
/>

ドラッグ機能

自由ドラッグ

📦

範囲制限付き

X軸のみ

<motion.div drag dragConstraints={constraintsRef} dragElastic={0.1} whileDrag={{ scale: 1.1 }} />

上のデモでは、自由にドラッグできる要素、範囲制限付きの要素、X軸のみに移動できる要素を試すことができます。

ドラッグ関連のprops

Props説明
dragtrue"x""y"でドラッグ方向を制限drag="x"
dragConstraintsドラッグの範囲(ref or オブジェクト){{ left: -100, right: 100 }}
dragElastic範囲外でのバウンド量(0-1)0.2(20%のバウンド)
dragMomentum慣性の有効/無効false(慣性無効)
dragTransitionドラッグ後のアニメーション設定{{ bounceStiffness: 600 }}
dragSnapToOriginドラッグ終了時に元の位置に戻るtrue

親要素を範囲として使用する

dragConstraintsにref(参照)を渡すと、その要素の範囲内でのみドラッグ可能になります。

TypeScript
function DraggableInContainer() {
  const constraintsRef = useRef(null);
  
  return (
    <div ref={constraintsRef} style={{ width: 300, height: 200 }}>
      <motion.div
        drag
        dragConstraints={constraintsRef}
      />
    </div>
  );
}

ポイント: dragElasticを0に設定すると、範囲外に出ようとしても完全に制限されます。1に近づけると、範囲外に引っ張ってから跳ね返る「ゴムバンド」のような動きになります。

レイアウトアニメーション

レイアウトアニメーションは、Framer Motionの最も強力な機能の一つです。通常、CSSでサイズや位置の変化をアニメーションさせるには、変更前後の値を計算し、適切なtransitionを設定する必要があります。

layoutpropを使用すると、Framer Motionが自動的に変更を検出し、スムーズにアニメーションします。開発者は何も計算する必要がありません。

layoutプロパティの仕組み

  1. Reactが再レンダリングを実行
  2. Framer Motionが要素の新しい位置・サイズを計算
  3. 変更前の状態から変更後の状態へ自動的にアニメーション
TypeScript
<motion.div layout>
  {isExpanded ? <ExpandedContent /> : <CollapsedContent />}
</motion.div>

これだけで、コンテンツの切り替え時にサイズがスムーズにアニメーションします。


layoutIdによる共有要素トランジション

layoutIdは、異なる場所にある要素同士を「同じもの」として認識させる機能です。リストからモーダルへの展開、タブ切り替え時のインジケーター移動など、「要素が移動する」演出を簡単に実現できます。

これは、ネイティブアプリでよく見られる「Shared Element Transition」をWebで実現するものです。

TypeScript
// カードリスト
{items.map(item => (
  <motion.div
    layoutId={`card-${item.id}`}
    onClick={() => setSelected(item.id)}
  >
    {item.title}
  </motion.div>
))}
 
// モーダル
<AnimatePresence>
  {selected && (
    <motion.div layoutId={`card-${selected}`}>
      <ExpandedCard />
    </motion.div>
  )}
</AnimatePresence>

レイアウトアニメーション

カードをクリックすると展開します(layoutId)

🎨デザイン
🚀開発
機能
💫アニメ

自動レイアウトアニメーション(layout prop)

クリックして展開
<motion.div layoutId="shared-element" /> <motion.div layout /> // 自動レイアウトアニメーション

上のデモでは、2つの機能を確認できます:

  1. layoutId: カードをクリックすると、リスト内のカードがモーダルに「変形」するように見える
  2. layout: 下部の要素をクリックすると、サイズ変更がスムーズにアニメーション

layoutの種類

説明使用例
true位置とサイズ両方をアニメーション一般的なレイアウト変更
"position"位置のみをアニメーション並べ替え可能なリスト
"size"サイズのみをアニメーションアコーディオン、展開パネル

実践的なパターン

ここでは、実際のプロジェクトでよく使われるアニメーションパターンを紹介します。これらのコードスニペットは、そのままコピーして使用したり、カスタマイズのベースとして活用できます。


ページトランジション

ページ間の移動時にアニメーションを追加すると、アプリケーション全体の一体感が向上します。Next.jsのPages Routerを使用している場合、_app.tsxAnimatePresenceを使用します。

TypeScript
// _app.tsx (Next.js Pages Router)
import { AnimatePresence, motion } from 'framer-motion';
 
function MyApp({ Component, pageProps, router }) {
  return (
    <AnimatePresence mode="wait">
      <motion.div
        key={router.route}
        initial={{ opacity: 0, y: 20 }}
        animate={{ opacity: 1, y: 0 }}
        exit={{ opacity: 0, y: -20 }}
        transition={{ duration: 0.3 }}
      >
        <Component {...pageProps} />
      </motion.div>
    </AnimatePresence>
  );
}

スクロールで表示されるセクション

ランディングページやブログ記事で、スクロールに応じてコンテンツがフェードインする演出です。whileInViewviewportを組み合わせます。

TypeScript
function Section({ children }) {
  return (
    <motion.section
      initial={{ opacity: 0, y: 50 }}
      whileInView={{ opacity: 1, y: 0 }}
      viewport={{ once: true, margin: '-100px' }}
      transition={{ duration: 0.6 }}
    >
      {children}
    </motion.section>
  );
}

ポイント:

  • viewport.once: true: 一度表示されたら再度アニメーションしない(パフォーマンス向上)
  • viewport.margin: トリガー位置を調整('-100px'で画面に入る100px前にアニメーション開始)

ローディングスピナー

無限回転するローディングスピナーです。repeat: Infinityで永続的にアニメーションします。

TypeScript
const spinnerVariants = {
  animate: {
    rotate: 360,
    transition: {
      duration: 1,
      repeat: Infinity,
      ease: 'linear'
    }
  }
};
 
function Spinner() {
  return (
    <motion.div
      variants={spinnerVariants}
      animate="animate"
      style={{
        width: 40,
        height: 40,
        border: '3px solid #e0e0e0',
        borderTop: '3px solid #667eea',
        borderRadius: '50%'
      }}
    />
  );
}

アコーディオン

FAQやサイドメニューでよく使われるアコーディオンです。height: 'auto'へのアニメーションはCSSでは難しいですが、Framer Motionなら簡単に実現できます。

TypeScript
function Accordion({ title, children, isOpen, onToggle }) {
  return (
    <div>
      <button onClick={onToggle}>{title}</button>
      <AnimatePresence initial={false}>
        {isOpen && (
          <motion.div
            initial={{ height: 0, opacity: 0 }}
            animate={{ height: 'auto', opacity: 1 }}
            exit={{ height: 0, opacity: 0 }}
            transition={{ duration: 0.3 }}
            style={{ overflow: 'hidden' }}
          >
            {children}
          </motion.div>
        )}
      </AnimatePresence>
    </div>
  );
}

ポイント:

  • initial={false}: AnimatePresenceに渡すと、初回マウント時のアニメーションをスキップ
  • overflow: 'hidden': 高さが変化する際にコンテンツがはみ出さないようにする

パフォーマンス最適化

Framer Motionは高度に最適化されていますが、使い方によってはパフォーマンスに影響を与えることがあります。以下のベストプラクティスを守ることで、60fpsのスムーズなアニメーションを維持できます。


1. transform系のプロパティを優先

xyscalerotateopacityGPUアクセラレーションが効くため高速です。これらはブラウザの「コンポジットレイヤー」で処理され、メインスレッドをブロックしません。

一方、widthheighttopleftなどは**レイアウト再計算(リフロー)**が発生するため、特に多数の要素がある場合に処理が重くなります。

TypeScript
// ✅ Good: transform系(GPU処理)
<motion.div animate={{ x: 100, scale: 1.2 }} />
 
// ❌ Avoid: レイアウト系(リフロー発生)
<motion.div animate={{ width: 200, left: 100 }} />

2. layoutプロパティの最適化

layoutプロパティは便利ですが、必要以上に使用するとパフォーマンスに影響します。位置またはサイズの一方だけが変化する場合は、適切な値を指定しましょう。

TypeScript
// position/sizeのどちらかだけ必要な場合
<motion.div layout="position" />  // 位置のみ
<motion.div layout="size" />      // サイズのみ

3. 不要な再レンダリングを避ける

Reactのstate更新は再レンダリングを引き起こしますが、useMotionValueを使用するとReactの再レンダリングなしでアニメーション値を更新できます。これは、ドラッグやスクロールなど、頻繁に値が変化する場面で特に有効です。

TypeScript
// useMotionValueを使用して再レンダリングを回避
import { motion, useMotionValue, useTransform } from 'framer-motion';
 
function OptimizedComponent() {
  const x = useMotionValue(0);
  const opacity = useTransform(x, [-100, 0, 100], [0, 1, 0]);
 
  // xが変化してもReactの再レンダリングは発生しない
  return <motion.div style={{ x, opacity }} drag="x" />;
}

その他のヒント

  • 大量の要素: リストに100以上の要素がある場合、すべてにアニメーションを適用するのは避ける
  • will-change: Framer Motionは自動的にwill-changeを設定するため、手動で追加する必要はない
  • reduce-motion: prefers-reduced-motionメディアクエリを尊重し、アクセシビリティに配慮する

まとめ

Framer Motionは、Reactアプリケーションにアニメーションを追加するための最も強力で使いやすいライブラリの一つです。宣言的なAPIにより、複雑なアニメーションも直感的に実装でき、パフォーマンスも最適化されています。

Framer Motionの強み

強み詳細
学習コストが低い宣言的なAPIで直感的。CSSアニメーションの知識がなくても始められる
機能が豊富ジェスチャー、レイアウト、SVGアニメーション、スクロール連動など幅広い機能
パフォーマンスGPUアクセラレーション、useMotionValueによる再レンダリング回避
TypeScriptサポート完全な型定義により、IDEの補完とエラーチェックが利用可能
エコシステム豊富なドキュメント、活発なコミュニティ、継続的なアップデート

使い分けの目安

ユースケース推奨機能難易度
初期表示アニメーションinitial / animate
ホバー・クリックwhileHover / whileTap
リスト表示variants + staggerChildren⭐⭐
モーダル・ページ遷移AnimatePresence + exit⭐⭐
スクロール連動useScroll / whileInView⭐⭐
ドラッグ操作drag + dragConstraints⭐⭐
レイアウト変化layout / layoutId⭐⭐⭐

次のステップ

  1. 基本をマスター: animateinitialtransitionを使った簡単なアニメーションから始める
  2. ジェスチャーを追加: whileHoverwhileTapでインタラクティブ性を向上
  3. バリアントを活用: 複数の要素を連動させるアニメーションを実装
  4. 高度な機能に挑戦: AnimatePresenceuseScrolllayoutで本格的なアニメーションを構築

Framer Motionを使いこなして、ユーザー体験を向上させるアニメーションを実装しましょう!

参考リンク