惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Microsoft Azure Blog
Microsoft Azure Blog
有赞技术团队
有赞技术团队
IT之家
IT之家
博客园 - 聂微东
Jina AI
Jina AI
Hugging Face - Blog
Hugging Face - Blog
Last Week in AI
Last Week in AI
Apple Machine Learning Research
Apple Machine Learning Research
WordPress大学
WordPress大学
小众软件
小众软件
爱范儿
爱范儿
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
V
Visual Studio Blog
雷峰网
雷峰网
酷 壳 – CoolShell
酷 壳 – CoolShell
阮一峰的网络日志
阮一峰的网络日志
宝玉的分享
宝玉的分享
博客园 - 三生石上(FineUI控件)
大猫的无限游戏
大猫的无限游戏
博客园 - Franky
量子位
月光博客
月光博客
博客园 - 【当耐特】
博客园 - 叶小钗

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Lottie vs Framer Motion: Which Should You Use?
Fazal Shah · 2026-06-01 · via DEV Community

Fazal Shah

Both Lottie and Framer Motion are popular animation tools for web apps, but they solve completely different problems. Using the wrong one will make your life harder. Here's how to pick.


The Core Difference

Lottie plays pre-built animations exported from a design tool (After Effects, Lottie Editor, etc.). The motion is defined entirely by the designer.

Framer Motion is a React animation library for animating DOM elements in code. The motion is defined entirely by the developer.

This isn't a competition — they're for different jobs.


When to Use Lottie

Use Lottie when:

  • The animation was created in After Effects, LottieFiles Editor, or similar
  • You need complex illustrated motion (characters, particles, morphing shapes)
  • The animation has a fixed, pre-designed visual style that must be pixel-perfect
  • You need micro-interactions from an icon library (animated icons, loading states)
  • File size is critical (convert to .lottie for 75% smaller — verify at IconKing)

Best use cases:

  • Hero animations and brand illustrations
  • Animated onboarding flows
  • Loading spinners and success animations
  • Animated icon sets
  • Complex path animations

When to Use Framer Motion

Use Framer Motion when:

  • You need to animate React components based on state changes
  • You need layout animations (elements moving position when others appear/disappear)
  • You need gesture-based animations (drag, hover, tap)
  • You need spring physics and momentum
  • You need orchestrated sequences across multiple components
  • You need scroll-based progress animations tied to scroll position

Best use cases:

  • Page transitions
  • Modal/drawer open-close animations
  • Drag-and-drop interfaces
  • Accordion/collapse animations
  • List item add/remove animations
  • Hover effects on UI components

Side-by-Side Comparison

Feature Lottie Framer Motion
Animation source Designer file (After Effects) Code
Complexity ceiling Very high (full AE support) Medium (CSS-level complexity)
Designer control 100% None
Developer control Limited (play/pause/speed) 100%
File size 10–200KB per animation ~45KB library
Bundle impact Per-animation One-time overhead
State-driven animation Limited Excellent
Gesture support None Built-in
Layout animation None Built-in
SSR support Needs guards Native

Bundle Size Reality

Lottie:

  • lottie-web: ~240KB gzipped (full build), ~150KB (light build)
  • @lottiefiles/dotlottie-web: ~50KB gzipped
  • Per animation: 5–200KB depending on complexity (use .lottie for 75% reduction)

Framer Motion:

  • Full bundle: ~45KB gzipped
  • Motion-safe subset (motion/react): ~17KB gzipped

If you only need a few simple loading animations, Lottie with dotLottie format can actually be lighter. If you need rich UI animations throughout your app, Framer Motion's single bundle overhead is more efficient.


Code Comparison

Loading Spinner

With Lottie:

import { DotLottieReact } from '@lottiefiles/dotlottie-react';

// Designer created this — developer just plays it
function Spinner() {
  return (
    <div role="status" aria-label="Loading">
      <DotLottieReact src="/animations/spinner.lottie" loop autoplay style={{ width: 48, height: 48 }} />
    </div>
  );
}

With Framer Motion:

import { motion } from 'framer-motion';

// Developer defines all motion in code
function Spinner() {
  return (
    <motion.div
      role="status"
      aria-label="Loading"
      style={{ width: 48, height: 48, borderRadius: '50%', border: '3px solid #e0e0e0', borderTop: '3px solid blue' }}
      animate={{ rotate: 360 }}
      transition={{ duration: 1, repeat: Infinity, ease: 'linear' }}
    />
  );
}


Modal Animation

With Lottie: You can't — Lottie doesn't animate DOM layout changes.

With Framer Motion:

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

function Modal({ isOpen, onClose, children }) {
  return (
    <AnimatePresence>
      {isOpen && (
        <motion.div
          initial={{ opacity: 0, y: 20 }}
          animate={{ opacity: 1, y: 0 }}
          exit={{ opacity: 0, y: 20 }}
          transition={{ duration: 0.2 }}
          style={{ position: 'fixed', top: '50%', left: '50%', transform: 'translate(-50%, -50%)' }}
        >
          {children}
        </motion.div>
      )}
    </AnimatePresence>
  );
}


Animated Icon (Hover State)

With Lottie (best choice for complex icons):

import Lottie from 'lottie-react';
import { useRef } from 'react';
import heartAnim from '/animations/heart.json';

function HeartButton() {
  const lottieRef = useRef(null);

  return (
    <button
      onMouseEnter={() => lottieRef.current?.play()}
      onMouseLeave={() => lottieRef.current?.stop()}
      aria-label="Like"
    >
      <div aria-hidden="true" style={{ width: 32, height: 32 }}>
        <Lottie lottieRef={lottieRef} animationData={heartAnim} loop={false} autoplay={false} />
      </div>
    </button>
  );
}

With Framer Motion (simpler icons):

import { motion } from 'framer-motion';

function HeartButton() {
  return (
    <motion.button
      whileHover={{ scale: 1.2 }}
      whileTap={{ scale: 0.9 }}
      aria-label="Like"
    >
      <svg>/* heart SVG path */</svg>
    </motion.button>
  );
}


Using Both Together

The best setups often use both:

import { motion, AnimatePresence } from 'framer-motion';
import { DotLottieReact } from '@lottiefiles/dotlottie-react';

function FormSubmit({ status }) {
  return (
    // Framer Motion handles the container animation
    <motion.div
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    >
      {status === 'loading' && (
        // Lottie handles the complex spinner animation
        <DotLottieReact src="/animations/spinner.lottie" loop autoplay style={{ width: 48, height: 48 }} />
      )}
      {status === 'success' && (
        // Lottie plays the success animation
        <DotLottieReact src="/animations/success.lottie" loop={false} autoplay style={{ width: 48, height: 48 }} />
      )}
    </motion.div>
  );
}

Use Framer Motion for UI state transitions. Use Lottie for the illustrations inside those transitions.


Decision Tree

Is the animation a pre-built file from a designer?
├── YES → Use Lottie
└── NO → Do you need layout animation, gestures, or spring physics?
          ├── YES → Use Framer Motion
          └── NO → Are you animating existing DOM elements?
                    ├── YES → Use Framer Motion (or CSS transitions)
                    └── NO → You probably need Lottie + a designer


Quick Take

  • Complex illustrated animations, brand motion, icon animations → Lottie
  • UI transitions, gestures, layout animations, state-driven motion → Framer Motion
  • Both → Use them together; they're complementary, not competing

Before committing to any Lottie file: preview it at IconKing — verify colors, timing, and convert to .lottie format for the smallest possible file size.