framer-motion vs react-transition-group vs react-native-reanimated vs react-spring vs lottie-react-native vs react-native-animatable
ReactおよびReact Nativeにおけるアニメーションライブラリの技術的比較
framer-motionreact-transition-groupreact-native-reanimatedreact-springlottie-react-nativereact-native-animatable類似パッケージ:

ReactおよびReact Nativeにおけるアニメーションライブラリの技術的比較

framer-motionlottie-react-nativereact-native-animatablereact-native-reanimatedreact-springreact-transition-groupはすべて、ReactやReact Nativeアプリケーションにアニメーションを導入するためのライブラリですが、それぞれ設計思想と適用領域が異なります。

framer-motionは主にWeb向けで、宣言的なAPIと物理ベースのアニメーションにより高品質なインタラクションを実現します。lottie-react-nativeはLottie JSONファイルをReact Nativeで再生するための専用ライブラリです。react-native-animatableはシンプルなプリセットアニメーションを提供し、導入が容易ですが柔軟性に欠けます。react-native-reanimatedはネイティブスレッド上でアニメーションを実行でき、パフォーマンス重視の複雑なジェスチャー対応UIに適しています。react-springは物理法則に基づくアニメーションエンジンで、WebとReact Nativeの両方をサポートします。react-transition-groupはCSSトランジションやアニメーションをReactコンポーネントのライフサイクルに連動させるための低レベルなユーティリティです。

npmのダウンロードトレンド

3 年

GitHub Starsランキング

統計詳細

パッケージ
ダウンロード数
Stars
サイズ
Issues
公開日時
ライセンス
framer-motion30,657,21831,0784.6 MB2155日前MIT
react-transition-group24,065,22410,258244 kB256-BSD-3-Clause
react-native-reanimated2,968,51710,6863.91 MB3438日前MIT
react-spring897,61029,0508.36 kB1345ヶ月前MIT
lottie-react-native873,53817,134290 kB1213日前Apache-2.0
react-native-animatable555,7199,95559.8 kB1702年前MIT

ReactおよびReact Nativeにおけるアニメーションライブラリの技術的比較

アニメーションは現代のUIにおいて必須の要素ですが、Reactエコシステムには目的や能力が大きく異なる複数のライブラリがあります。この記事では、framer-motionlottie-react-nativereact-native-animatablereact-native-reanimatedreact-springreact-transition-groupの6つを、実際の開発シナリオに基づいて深く比較します。

🎯 アニメーションの種類と実行場所

Web vs React Native

まず重要なのは、ターゲットプラットフォームです。

  • Web専用: framer-motion, react-spring (Web版), react-transition-group
  • React Native専用: lottie-react-native, react-native-animatable, react-native-reanimated
  • クロスプラットフォーム: react-spring(WebとReact Nativeの両方をサポート)

⚠️ 注意: framer-motionはReact Nativeでは動作しません。同様に、lottie-react-nativeはWebでは使えません(Web向けにはlottie-webまたはlottie-reactを使用)。

アニメーションの実行場所

パフォーマンスに大きく影響するのが「どこでアニメーションが実行されるか」です。

  • JavaScriptスレッド: react-native-animatable, react-spring(一部)
    • メインスレッドで実行されるため、重い処理があるとカクつく可能性あり
  • ネイティブスレッド: react-native-reanimated
    • UIスレッドとは分離され、60fpsを安定して維持可能
  • CSS / ネイティブレンダラー: framer-motion, react-transition-group, lottie-react-native
    • ハードウェアアクセラレーションを利用し、スムーズな描画を実現

🧪 基本的なフェードインアニメーションの実装比較

最もシンプルなケース — コンポーネントの表示時にフェードイン — で各ライブラリの使い方を見てみましょう。

framer-motion(Web)

import { motion } from 'framer-motion';

function FadeIn() {
  return (
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      transition={{ duration: 0.5 }}
    >
      Hello World
    </motion.div>
  );
}

lottie-react-native(React Native)

Lottieは事前作成されたJSONアセットを再生するため、フェードインのような単純なアニメーションには不向きですが、一応表示は可能です。

import LottieView from 'lottie-react-native';

function LottieFade() {
  return (
    <LottieView
      source={require('./fade-in.json')}
      autoPlay
      loop={false}
    />
  );
}

react-native-animatable(React Native)

import Animatable from 'react-native-animatable';

function FadeIn() {
  return (
    <Animatable.View animation="fadeIn" duration={500}>
      <Text>Hello World</Text>
    </Animatable.View>
  );
}

react-native-reanimated(React Native)

import { View } from 'react-native';
import Animated, { useSharedValue, useAnimatedStyle, withTiming } from 'react-native-reanimated';

function FadeIn() {
  const opacity = useSharedValue(0);

  // 初期表示時にアニメーション開始
  useEffect(() => {
    opacity.value = withTiming(1, { duration: 500 });
  }, []);

  const animatedStyle = useAnimatedStyle(() => ({
    opacity: opacity.value,
  }));

  return (
    <Animated.View style={[{ padding: 20 }, animated-style]}>
      <Text>Hello World</Text>
    </Animated.View>
  );
}

react-spring(WebまたはReact Native)

// Webの場合
import { animated, useSpring } from '@react-spring/web';

function FadeIn() {
  const props = useSpring({ opacity: 1, from: { opacity: 0 }, config: { duration: 500 } });
  return <animated.div style={props}>Hello World</animated.div>;
}

// React Nativeの場合
import { AnimatedView, useSpring } from '@react-spring/native';

function FadeIn() {
  const props = useSpring({ opacity: 1, from: { opacity: 0 }, config: { duration: 500 } });
  return <AnimatedView style={props}><Text>Hello World</Text></AnimatedView>;
}

react-transition-group(Web)

import { CSSTransition } from 'react-transition-group';
import './Fade.css'; // CSSでopacityのtransitionを定義

function FadeIn({ in: inProp }) {
  return (
    <CSSTransition in={inProp} timeout={500} classNames="fade">
      <div>Hello World</div>
    </CSSTransition>
  );
}

/* Fade.css */
.fade-enter {
  opacity: 0;
}
.fade-enter-active {
  opacity: 1;
  transition: opacity 500ms;
}

🌀 複雑なインタラクション:ドラッグ&スナップ

次に、より高度なユースケース — ドラッグ可能なカードを左右にスワイプしてスナップする — を比較します。

framer-motion(Web)

import { motion, useMotionValue, useTransform } from 'framer-motion';

function DraggableCard() {
  const x = useMotionValue(0);
  const rotate = useTransform(x, [-100, 100], [-10, 10]);

  return (
    <motion.div
      drag="x"
      dragConstraints={{ left: -100, right: 100 }}
      style={{ x, rotate }}
      dragSnapToOrigin
    >
      Swipe me
    </motion.div>
  );
}

react-native-reanimated(React Native)

import { PanGestureHandler } from 'react-native-gesture-handler';
import Animated, {
  useSharedValue,
  useAnimatedGestureHandler,
  useAnimatedStyle,
  withSpring,
} from 'react-native-reanimated';

function DraggableCard() {
  const translateX = useSharedValue(0);

  const gestureHandler = useAnimatedGestureHandler({
    onStart: (_, ctx) => {
      ctx.startX = translateX.value;
    },
    onActive: (event, ctx) => {
      translateX.value = ctx.startX + event.translationX;
    },
    onEnd: () => {
      if (Math.abs(translateX.value) > 50) {
        translateX.value = withSpring(translateX.value > 0 ? 100 : -100);
      } else {
        translateX.value = withSpring(0);
      }
    },
  });

  const animatedStyle = useAnimatedStyle(() => ({
    transform: [{ translateX: translateX.value }],
  }));

  return (
    <PanGestureHandler onGestureEvent={gestureHandler}>
      <Animated.View style={[styles.card, animatedStyle]}>
        <Text>Swipe me</Text>
      </Animated.View>
    </PanGestureHandler>
  );
}

react-spring(Web)

import { useDrag } from '@use-gesture/react';
import { animated, useSpring } from '@react-spring/web';

function DraggableCard() {
  const [{ x, rotate }, api] = useSpring(() => ({ x: 0, rotate: 0 }));

  const bind = useDrag(({ offset: [ox], last }) => {
    if (last) {
      if (Math.abs(ox) > 50) {
        api.start({ x: ox > 0 ? 100 : -100, rotate: ox > 0 ? 10 : -10 });
      } else {
        api.start({ x: 0, rotate: 0 });
      }
    } else {
      api.start({ x: ox, rotate: ox / 10 });
    }
  });

  return <animated.div {...bind()} style={{ x, rotate }}>Swipe me</animated.div>;
}

💡 注: lottie-react-nativereact-native-animatablereact-transition-groupはこのようなインタラクティブなドラッグ操作には対応していません。

📱 パフォーマンスと制限

react-native-animatableの現状

公式GitHubリポジトリ(https://github.com/oblador/react-native-animatable)によると、このライブラリは現在**メンテナンスモード**に入っており、新機能の追加は行われていません。単純なアニメーションには引き続き使えますが、新しいプロジェクトでは`react-native-reanimated`や`react-spring`を検討すべきです。

react-native-reanimatedの制約

  • ネイティブスレッドで実行されるため、JavaScriptのロジック(例:console.log、カスタム関数)をアニメーション中に直接実行できません。
  • デバッグが難しく、エラーメッセージが分かりにくいことがあります。
  • ジェスチャー処理にはreact-native-gesture-handlerとの併用が必須です。

framer-motionの強み

  • layoutプロパティを使うと、要素のサイズや位置が変更された際に自動でスムーズなトランジションを適用できます。
  • whileHoverwhileTapなどのインタラクションハンドラが組み込みで提供されています。
<motion.button
  whileHover={{ scale: 1.1 }}
  whileTap={{ scale: 0.95 }}
>
  Click me
</motion.button>

🔁 状態駆動型アニメーションの比較

UI状態(例:開閉、選択)に応じてアニメーションを切り替えるケースです。

react-spring

const [{ height }, api] = useSpring(() => ({ height: 0 }));

const toggle = () => {
  api.start({ height: isOpen ? 0 : 200 });
};

return (
  <animated.div style={{ height, overflow: 'hidden' }}>
    Content
  </animated.div>
);

framer-motion

<motion.div
  animate={{ height: isOpen ? 200 : 0 }}
  transition={{ duration: 0.3 }}
  style={{ overflow: 'hidden' }}
>
  Content
</motion.div>

react-transition-group

<CSSTransition in={isOpen} timeout={300} classNames="slide">
  <div>Content</div>
</CSSTransition>

/* CSSでheightのtransitionを定義 */

🧩 適切なライブラリの選び方:まとめ

ユースケース推奨ライブラリ
Web向け高品質インタラクション(ページ遷移、ドラッグ、スクロール連動)framer-motion
React NativeでLottie JSONを再生lottie-react-native
React Nativeで簡単なフェード・スライドアニメーション(小規模プロジェクト)react-native-animatable(※新規プロジェクトでは避けるべき)
React Nativeで高性能なジェスチャー対応UI(例:カスタムナビゲーション)react-native-reanimated
物理ベースの自然なアニメーションをWebとReact Nativeで共通化react-spring
CSSトランジションをReactのマウント/アンマウントに連動react-transition-group

💡 最終的なアドバイス

  • Web開発者: framer-motionが多くのケースで最適です。ただし、非常にシンプルなトランジションならreact-transition-groupで十分な場合もあります。
  • React Native開発者:
    • Lottieを使うなら → lottie-react-native
    • 複雑でパフォーマンスが重要なUIなら → react-native-reanimated
    • クロスプラットフォームで物理アニメーションを使いたいなら → react-spring
    • 単純なアニメーションで急いでいるなら → react-native-animatable(ただし長期的には移行を検討)

どのライブラリを選ぶにせよ、アニメーションは「目的」ではなく「手段」であることを忘れないでください。ユーザー体験を向上させるために、適切なツールを選びましょう。

選び方: framer-motion vs react-transition-group vs react-native-reanimated vs react-spring vs lottie-react-native vs react-native-animatable

  • framer-motion:

    framer-motionは、Web向けの高度なインタラクション(ページ遷移、ドラッグ操作、スクロール連動など)を実装したい場合に最適です。特にデザインシステムとの統合や、モーションの微調整が必要なプロダクトで力を発揮します。ただし、React Nativeでは使用できません。

  • react-transition-group:

    react-transition-groupは、CSSトランジションやキーフレームアニメーションをReactのマウント・アンマウントタイミングに連動させたい場合に使います。例えば、モーダルの表示・非表示やリストアイテムの追加・削除時の滑らかな演出に適しています。独自のアニメーションエンジンは持たず、既存のCSSと連携する点が特徴です。

  • react-native-reanimated:

    react-native-reanimatedは、ネイティブスレッドでアニメーションを実行できるため、60fpsを維持する必要がある複雑なUI(例:カスタムナビゲーション、スワイプ可能なリスト、高度なジェスチャー)に最適です。ただし、学習コストが高く、デバッグも難しいため、単純なアニメーションにはオーバーキルです。

  • react-spring:

    react-springは、物理ベースの自然な動き(バネ、減衰など)をWebとReact Nativeの両方で実現したい場合に有効です。アニメーションの状態管理が直感的で、パフォーマンスも良好ですが、Lottieのような事前作成済みアセットの再生には使えません。

  • lottie-react-native:

    lottie-react-nativeは、デザイナーがAdobe After Effectsで作成したLottie JSONアニメーションをReact Nativeアプリ内で忠実に再生したい場合に選択します。ベクター形式で軽量かつスケーラブルですが、インタラクティブな制御(例:ユーザー入力に応じた変化)には向いていません。

  • react-native-animatable:

    react-native-animatableは、すぐに使えるプリセットアニメーション(フェードイン、スライドなど)を手軽に導入したい場合に向いています。小規模なプロジェクトやプロトタイピングに便利ですが、カスタムアニメーションや高性能なジェスチャー対応UIには不向きです。

framer-motion のREADME

Motion logo
Motion for React

An open source animation library
for React

npm version npm downloads per month jsDelivr hits (npm) NPM License

npm install motion

Table of Contents

  1. Why Motion?
  2. 🍦 Platforms
  3. 🎓 Examples
  4. ⚡️ Motion+
  5. 👩🏻‍⚖️ License
  6. 💎 Contribute
  7. ✨ Sponsors

Why Motion?

  • Simple API: First-class React, JavaScript, and Vue packages.
  • Hybrid engine: Power of JavaScript combined with native browser APIs for 120fps, GPU-accelerated animations.
  • Production-ready: TypeScript, extensive test suite, tree-shakable, tiny footprint. Batteries included: Gestures, springs, layout transitions, scroll-linked effects, timelines.

🍦 Platforms

Motion is available for React, JavaScript and Vue.

React
import { motion } from "motion/react"

function Component() {
    return <motion.div animate={{ x: 100 }} />
}

Get started with Motion for React.

JavaScript
import { animate } from "motion"

animate("#box", { x: 100 })

Get started with JavaScript.

Vue
<script>
    import { motion } from "motion-v"
</script>

<template> <motion.div :animate={{ x: 100 }} /> </template>

Get started with Motion for Vue.

🎓 Examples

Browse 100+ free and 180+ premium Motion Examples, with copy-paste code that'll level-up your animations whether you're a beginner or an expert.

⚡️ Motion+

A one-time payment, lifetime-updates membership:

  • 180+ premium examples
  • Premium APIs like Cursor and Ticker
  • Visual editing for VS Code (alpha)
  • Private Discord
  • Early access content

Get Motion+

👩🏻‍⚖️ License

  • Motion is MIT licensed.

💎 Contribute

✨ Sponsors

Motion is sustainable thanks to the kind support of its sponsors.

Become a sponsor

Partners

Motion powers the animations for all websites built with Framer, the web builder for creative pros. The Motion website itself is built on Framer, for its delightful canvas-based editing and powerful CMS features.

Framer

Motion drives the animations on the Cursor homepage, and is working with Cursor to bring powerful AI workflows to the Motion examples and docs.

Cursor

Platinum

Linear Figma Sanity Sanity Clerk

Gold

Liveblocks Luma LottieFiles

Silver

Frontend.fyi Firecrawl Puzzmo Bolt.new

Personal