framer-motion、gsap、popmotion 和 react-spring 都是用于在 Web 应用中创建动画的 JavaScript 库,但它们的 design 理念和适用场景各不相同。framer-motion 是专为 React 设计的声明式动画库,提供强大的布局动画和手势支持。gsap 是行业标准的高性能动画引擎,擅长复杂的时间轴控制,不限框架。react-spring 基于物理弹簧模型,提供自然的交互动画,深度集成 React。popmotion 是底层的函数式动画引擎,framer-motion 正是基于它构建的,适合需要完全控制动画曲线的底层开发。
在前端开发中,动画不仅是视觉装饰,更是用户体验的核心组成部分。framer-motion、gsap、popmotion 和 react-spring 代表了四种不同的动画解决思路。作为架构师,我们需要理解它们底层的工作原理,以便在性能、开发效率和可维护性之间做出正确权衡。
动画库如何与 React 结合,直接决定了代码的可读性和维护成本。
framer-motion 采用完全声明式的组件封装。
<motion.div> 替代普通 HTML 标签。// framer-motion: 声明式组件
import { motion } from "framer-motion";
function Box() {
return <motion.div animate={{ x: 100 }} />;
}
gsap 传统上是命令式的,但通过官方 React 插件提供了 Hooks 支持。
ref 获取 DOM 节点。useGSAP 钩子中编写命令式动画逻辑。// gsap: 命令式 + Hooks
import { useGSAP } from "@gsap/react";
import { gsap } from "gsap";
function Box() {
const ref = useRef(null);
useGSAP(() => {
gsap.to(ref.current, { x: 100 });
});
return <div ref={ref} />;
}
react-spring 采用混合模式,返回动画值绑定到样式。
useSpring 获取动画值。<animated.div> 包裹以接收动态样式。// react-spring: 混合式
import { useSpring, animated } from "@react-spring/web";
function Box() {
const { x } = useSpring({ x: 100 });
return <animated.div style={{ x }} />;
}
popmotion 是纯函数式的,不绑定特定框架。
// popmotion: 函数式
import { animate } from "popmotion";
function Box() {
const ref = useRef(null);
useEffect(() => {
animate({
from: 0,
to: 100,
onUpdate: (v) => (ref.current.style.transform = `translateX(${v}px)`)
});
}, []);
return <div ref={ref} />;
}
不同的动画模型决定了运动的“手感”和配置复杂度。
framer-motion 支持关键帧和弹簧两种模型。
type: "spring" 实现物理效果。// framer-motion: 支持双模型
<motion.div
animate={{ x: 100 }}
transition={{ type: "spring", stiffness: 100 }}
/>
gsap 核心是基于时间的关键帧(Tween)。
ease 参数模拟物理效果。// gsap: 关键帧为主
gsap.to(".box", {
x: 100,
duration: 1,
ease: "elastic.out(1, 0.3)"
});
react-spring 专注于物理弹簧模型。
mass、tension、friction。// react-spring: 物理弹簧
useSpring({
from: { x: 0 },
to: { x: 100 },
config: { mass: 1, tension: 200, friction: 20 }
});
popmotion 提供底层的动画原语。
keyframes 或 spring 算法。// popmotion: 底层原语
animate({
from: 0,
to: 100,
type: "spring",
stiffness: 100,
onUpdate: (v) => console.log(v)
});
当多个动画需要按顺序或同时发生时,编排能力至关重要。
framer-motion 提供声明式的编排工具。
transition 中的 delay 或 staggerChildren。useAnimation 控制。// framer-motion: 声明式编排
<motion.ul>
{items.map((item) => (
<motion.li
key={item}
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ delay: 0.1 }}
/>
))}
</motion.ul>
gsap 拥有最强大的时间轴系统。
gsap.timeline() 精确控制每个片段。// gsap: 时间轴编排
const tl = gsap.timeline();
tl.to(".box1", { x: 100 })
.to(".box2", { x: 100 }, "+=0.5");
react-spring 依赖链式调用或延迟配置。
useChain 管理多个引用顺序。delay 时间。// react-spring: 链式编排
useChain(
[springRef1, springRef2],
[0, 0.5], // timeOffsets
[1000, 1000] // timeSteps
);
popmotion 通过组合动作实现编排。
sequence 函数组合多个动画。// popmotion: 动作序列
sequence([
animate({ from: 0, to: 100, duration: 1 }),
animate({ from: 100, to: 200, duration: 1 })
]);
动画性能直接影响用户设备的电池寿命和帧率。
framer-motion 自动优化渲染。
// framer-motion: 自动优化
// 自动将 x/y 转换为 translate3d
<motion.div animate={{ x: 100, y: 100 }} />
gsap 提供极致的性能控制。
// gsap: 强制 GPU
gsap.to(".box", {
x: 100,
force3D: true,
overwrite: true
});
react-spring 每一帧都可能触发 React 渲染。
// react-spring: 渲染绑定
// 每次弹簧更新都可能触发组件重渲染
const { x } = useSpring({ x: target });
return <animated.div style={{ x }} />;
popmotion 直接操作 DOM 或值。
// popmotion: 直接操作
animate({
from: 0,
to: 100,
onUpdate: (v) => {
// 直接修改样式,跳过 React 渲染
element.style.opacity = v;
}
});
| 特性 | framer-motion | gsap | react-spring | popmotion |
|---|---|---|---|---|
| 主要场景 | React UI 交互 | 复杂营销页/时间轴 | 物理交互动画 | 底层引擎/自定义 |
| API 风格 | 声明式组件 | 命令式 + Hooks | Hooks + 样式绑定 | 函数式 |
| 动画模型 | 关键帧 + 弹簧 | 关键帧 (Tween) | 物理弹簧 | 可配置原语 |
| 时间轴 | 声明式编排 | 强大 Timeline | 链式调用 | 动作序列 |
| 学习曲线 | 低 | 中 | 中 | 高 |
| 授权许可 | MIT (免费) | 商业/免费混合 | MIT (免费) | MIT (免费) |
framer-motion 是 React 项目的默认首选 🏆。它在开发体验和功能之间取得了最佳平衡,能覆盖 90% 的 UI 动画需求。它的声明式 API 让动画成为组件逻辑的一部分,而不是副作用。
gsap 是复杂动画的专业工具 🛠️。当你需要制作获奖级别的滚动动画、复杂的时间轴序列,或者需要在非 React 环境中复用动画逻辑时,它是唯一选择。但请注意检查商业授权条款。
react-spring 适合特定交互场景 🎈。如果你的产品核心体验依赖于“真实感”的物理反馈(如拖拽、弹跳),它的弹簧模型比关键帧更自然。但要注意性能开销。
popmotion 是底层基石 🧱。除非你在构建自己的动画库,或者需要极度定制化的动画逻辑,否则在 React 项目中建议直接使用 framer-motion。它是引擎,而 Framer 是整车。
popmotion 定位:虽然 popmotion 未被官方标记为废弃,但维护重心已转向 framer-motion。在新 React 项目中,除非有特殊底层需求,否则不建议直接使用 popmotion。gsap 授权:gsap 的核心功能免费,但部分高级插件(如 ScrollTrigger 的某些用法、SplitText)需要商业许可证。在企业项目中务必合规审查。react-spring 或 framer-motion 中动画化大量 DOM 节点。对于列表超过 100 项的动画,考虑虚拟化或切换到 gsap/popmotion 的直接 DOM 操作。没有绝对的“最佳”,只有“最适合”。
framer-motion。gsap。react-spring。popmotion。理解这些工具的本质差异,能帮助你在架构设计初期就避开性能陷阱,并为团队选择最高效的开发路径。
如果你的项目基于 React 且需要快速实现复杂的界面交互、布局动画或手势反馈,选择 framer-motion。它的声明式 API 与 React 组件模型完美契合,能大幅减少样板代码,适合大多数现代 React 应用。
如果你需要制作高强度的营销页面、复杂的时间轴动画或需要跨框架(如 Vue、Vanilla JS)复用动画逻辑,选择 gsap。它在性能优化和时间轴控制方面最为强大,但需要注意商业授权许可。
如果你正在构建自定义动画库或非 React 项目,且需要底层的动画原语(如值追踪、物理引擎),选择 popmotion。对于常规 React 业务开发,通常建议直接使用基于它构建的 framer-motion 以获得更好的体验。
如果你追求基于物理真实感的交互动画(如拖拽回弹、自然减速),且希望动画状态与 React 渲染周期深度绑定,选择 react-spring。它适合需要高度定制化物理参数的交互场景。
npm install motion
Motion is available for React, JavaScript and Vue.
import { motion } from "motion/react"
function Component() {
return <motion.div animate={{ x: 100 }} />
}
Get started with Motion for React.
Note: Framer Motion is now Motion. Import from motion/react instead of framer-motion.
import { animate } from "motion"
animate("#box", { x: 100 })
Get started with JavaScript.
<script>
import { motion } from "motion-v"
</script>
<template> <motion.div :animate={{ x: 100 }} /> </template>
Get started with Motion for Vue.
Browse 330+ official examples, with copy-paste code that'll level-up your animations whether you're a beginner or an expert.
Over 100 examples come with a full step-by-step tutorial.
A one-time payment, lifetime-updates membership:
Motion is sustainable thanks to the kind support of its sponsors.
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.
Motion drives the animations on the Cursor homepage, and is working with Cursor to bring powerful AI workflows to the Motion examples and docs.