Skip to content

title: Motion tools comparison applies_to: [motion, animation, tools] version: 1.0.0 last_updated: 2026-05 stability: stable


Motion tools comparison

Designers and developers split the work of motion. The tool depends on who creates and how complex.

Decision tree

Is the motion < 200ms and triggered by user input?
  ├── Yes → CSS transition / animation
  └── No
      ├── Designer-led, complex sequence?
      │   ├── Yes, interactive → Rive
      │   └── Yes, non-interactive → Lottie
      └── Engineer-led, in React?
          ├── Simple → Framer Motion
          ├── Timeline-based, complex → GSAP
          └── Physics / springs → react-spring

Six tools, when to use each

1. CSS animations / transitions

Use for: hover, press feedback, state changes, simple entrances.

Built into the browser. No bundle cost. Universally supported.

.button {
  transition: transform 100ms ease-out, opacity 100ms ease-out;
}
.button:active {
  transform: scale(0.97);
  opacity: 0.85;
}

@keyframes shimmer {
  0%   { background-position: -200% 0; }
  100% { background-position: 200% 0; }
}

Limitations: - No JS-driven control (can't pause / scrub / sequence imperatively). - Limited to single elements (no choreographing many). - No state-machine animations.

For 80% of micro-interactions: CSS is the right answer.

2. Framer Motion (React)

Use for: React apps. Component entrances, page transitions, shared elements (layoutId), choreographed sequences.

import { motion, AnimatePresence } from "framer-motion";

<motion.div
  initial={{ opacity: 0, y: 8 }}
  animate={{ opacity: 1, y: 0 }}
  exit={{ opacity: 0 }}
  transition={{ duration: 0.2, ease: "easeOut" }}
>
  Content
</motion.div>

Strengths: - React-native API (declarative). - Layout animations (layout prop, FLIP technique built-in). - Shared element transitions (layoutId). - Drag, gesture support. - Variants (orchestrate parent → children). - AnimatePresence for exits.

Bundle cost: ~30 kB gz. Use LazyMotion + domAnimation to slim to ~7 kB for simple needs.

When NOT to use: - Non-React apps. - Simple CSS hovers (overkill). - Timeline-heavy sequences (GSAP is better).

3. GSAP (GreenSock)

Use for: complex marketing sequences, scroll-triggered animations, timeline-based choreography. Framework-agnostic.

gsap.timeline()
  .from(".hero-headline", { y: 40, opacity: 0, duration: 0.6 })
  .from(".hero-sub", { y: 20, opacity: 0, duration: 0.5 }, "-=0.4")
  .from(".hero-cta", { scale: 0.9, opacity: 0, duration: 0.4 }, "-=0.3")
  .from(".hero-visual", { x: 80, opacity: 0, duration: 0.7 }, "-=0.5");

Strengths: - ScrollTrigger plugin — best-in-class for scroll-driven motion. - Timeline — precise control over sequence timing. - Performance — heavily optimized, 60fps on complex scenes. - Framework-agnostic (works in React, Vue, vanilla, etc.).

License: MIT for non-business use; paid for commercial use of certain plugins (ScrollTrigger, MorphSVG, etc.). Check current pricing.

Bundle: 30–60 kB depending on plugins.

When NOT to use: - Simple CSS fades (overkill). - Pure micro-interactions (CSS is faster).

4. Lottie

Use for: designer-created animations exported from After Effects, used as JSON.

import Lottie from "lottie-react";
import animationData from "./checkmark-success.json";

<Lottie animationData={animationData} loop={false} />

Workflow: 1. Designer animates in After Effects. 2. Export with Bodymovin plugin → JSON. 3. Engineer drops JSON into runtime (React, RN, iOS, Android, web).

Strengths: - Designer-led — designers create motion in their familiar tool. - Cross-platform — same JSON runs on web, iOS, Android, RN. - Vector-based — scales to any size cleanly. - Best for: brand logos animated, success / error states with motion, hero illustrations.

When NOT to use: - Interactive animations (Lottie can play / pause / scrub but not state-machine — use Rive instead). - Animations that should respond to user input (use Rive). - Tiny micro-interactions (overkill; CSS faster).

Bundle: lottie-web is ~150 kB. Use lottie-react-light (~50 kB) if you don't need all features.

5. Rive

Use for: interactive animations with state machines. Designer + engineer collaborate.

import { useRive } from "@rive-app/react-canvas";

function HeartButton() {
  const { rive, RiveComponent } = useRive({
    src: "/animations/heart.riv",
    stateMachines: "Like Button",
    autoplay: true,
  });

  return (
    <button onClick={() => rive?.fireState("Like Button", "Click")}>
      <RiveComponent />
    </button>
  );
}

Strengths: - State machines — animations respond to events / inputs. - Smaller files than Lottie (binary format). - Designer-friendly tool (rive.app). - Cross-platform: web, iOS, Android, RN, Flutter, Unity, Unreal.

Best for: - Interactive characters (mascots that react). - Button states (idle → hover → press → success). - Onboarding flow visuals. - Game UI (character emotes, etc.).

When NOT to use: - Static animation clips (Lottie is fine). - Design-system-internal motion (CSS / Framer Motion fits closer to code).

Bundle: ~150 kB runtime.

6. react-spring (React)

Use for: physics-based motion that responds to user input naturally.

import { useSpring, animated } from "@react-spring/web";

function Card() {
  const styles = useSpring({
    from: { scale: 0.9, opacity: 0 },
    to: { scale: 1, opacity: 1 },
    config: { tension: 280, friction: 60 },
  });

  return <animated.div style={styles}>...</animated.div>;
}

Strengths: - Spring physics — natural feeling motion (no fixed durations). - Imperative + declarative APIs. - Smaller than Framer Motion (~17 kB).

When NOT to use: - You don't need spring physics — Framer Motion is more featureful. - You're outside React.

Bundle: ~17 kB.

When to pick which (decision matrix)

Need Tool
Hover, press, focus rings CSS
Loading shimmers CSS
Page transitions in React Framer Motion
Modal entrances in React Framer Motion
List re-orders (FLIP) Framer Motion layout prop
Hero / shared-element morph Framer Motion layoutId OR View Transitions API
Scroll-driven parallax GSAP ScrollTrigger
Marketing storyboard (3+ second sequence) GSAP timeline OR Lottie
Brand-led illustrated success state Lottie
Interactive mascot / character Rive
Onboarding visuals that react Rive
Drag-and-drop with physics react-spring or Framer Motion
Cross-platform (web + iOS + Android) Lottie or Rive

Performance comparison

Tool First load Per-animation cost
CSS 0 kB Minimal (GPU-composited)
Framer Motion 7–30 kB gz Low (DOM + transforms)
GSAP 30–60 kB gz Low (highly optimized)
Lottie 50–150 kB Medium (canvas / SVG rendering)
Rive ~150 kB Low (canvas, optimized)
react-spring 17 kB Low

For most apps: CSS + Framer Motion ≈ 20-40 kB total motion budget. Don't add Lottie / Rive unless designer-created animation justifies it.

Korean / Toss-style preference

Toss / KakaoBank-style apps often use: - CSS for micro-interactions - Framer Motion for app transitions - Lottie for brand moments (success animations, money-flow demos) - Rarely GSAP (less common in Korean tech stacks)

Reduced motion handling

Tool Reduced-motion support
CSS Native via @media (prefers-reduced-motion: reduce)
Framer Motion useReducedMotion() hook
GSAP Manual: check matchMedia("(prefers-reduced-motion)") and disable timelines
Lottie Pause / show single frame
Rive Pause state machine; show "rest" state

Implement always. Don't ship without it.

Don't

  • Don't load Lottie just to do a fade-in.
  • Don't import Framer Motion for one CSS-doable hover.
  • Don't ship 4 different motion libraries in one app.
  • Don't auto-play Lottie / Rive for purely decorative effect (battery drain).
  • Don't use library-specific easings without exposing them as tokens.

Cross-reference