先分清:这不是两个同层面的库
在 React 社区里选动画方案,最终绕不开 React Spring 和 Framer Motion。这个问题的热度一直很高,不是没有道理:它们分别代表了两种动画设计路线,一个强调物理模拟,一个强调声明式状态绑定。很多人会被’物理动画’这个词吸引,也有人被 Framer Motion 的 API 简洁度征服。但选型不能只看标签,得看它解决的问题,以及你将要面对的工程约束。

说得直接一点,React Spring 首先是一个动画引擎,它的核心是弹簧物理模型;Framer Motion 更像是一套为 React 量身定做的动画 API,它把动画直接挂在组件的状态和属性上。两者都叫’动画库’,但上手方式、表达能力和维护成本完全不一样。如果你只是在两个库之间比一个’哪个更好’,多半会在实际项目里翻车。
React Spring:把动画当成一套物理系统
React Spring 的灵感来自物理世界的弹簧。它的动画不是按时间线性推进,而是让一组数值在刚度、阻尼、质量等参数下’自然’地逼近目标值。这带来的第一个好处是:动画可以被打断,也可以无限地重新定向。当用户快速拖拽一个元素时,你不需要手动管理时间轴和缓动曲线,只需要更新目标值,弹簧会自动处理中间状态。
这种模型天然的适合手势、拖拽、滚动联动,以及多个数值之间需要保持相对节奏的场景。比如一个图形编辑器里的元素在画布上移动,或者一个实时刷新的大屏数字在变化时带有弹性,React Spring 都能处理得比较自然。
但物理模型的代价也很明显。第一,概念上你需要理解弹簧参数:stiffness(刚度)控制弹性,damping(阻尼)控制衰减,mass(质量)影响响应速度。第二,当动画需要严格依赖时间轴(比如等待 300ms 再播放,或者某个动画必须精确 500ms 完成)时,物理模型反而会添乱。这时候你会用它模拟一个近似的时间曲线,但总觉得不够直接。
Framer Motion:让动画成为 React 状态的一部分
Framer Motion 走的是另一条路。它几乎没有’动画引擎’的即视感,而是把动画变成 JSX 的声明式属性:你告诉组件最终的状态,它负责补完中间过程。这种设计非常贴近 React 心智模型,尤其适合产品 UI 里的进入、退出、布局变化、列表重排等常见交互。
比如 AnimatePresence 可以优雅地处理组件卸载时的退场动画;layout 属性则能自动计算组件位置变化并插补动画。这些能力在构建复杂界面时非常省心,不需要你去手写进入和离开时机的协调逻辑。Framer Motion 内部同样使用了弹簧和贝塞尔曲线等参数,但这些细节都被藏到了 transition 配置里,日常开发大多数时候不需要关心。
它让我印象最深的一点是类型友好。Motion 组件可以直接给 style 和 animate 传入 TS 类型推断,在编辑器的补全提示下,几乎没有记忆成本。对于一个团队来说,新成员能很快上手并写出还不错的动画代码,这是 Framer Motion 很大的隐形收益。
同一个效果,两种写法的直观对比
为了让差异更具体,我们拿一个最简单的场景:点击一个元素,让它向右移动 100 像素。分别用 React Spring 和 Framer Motion 实现。
React Spring 的典型写法:
import { useSpring, animated } from '@react-spring/web'
const App = () => {
const [pos, setPos] = useState(0)
const spring = useSpring({
from: { x: 0 },
to: { x: pos }
})
return (
<animated.div
style={spring}
=> setPos(pos === 0 ? 100 : 0)}
>
click me
</animated.div>
)
}
Framer Motion 的写法更直接:
import { motion } from 'framer-motion'
const App = () => {
const [pos, setPos] = useState(0)
return (
<motion.div
animate={{ x: pos }}
transition={{ type: 'spring', stiffness: 170, damping: 26 }}
=> setPos(pos === 0 ? 100 : 0)}
>
click me
</motion.div>
)
}
注意两者的核心差异:React Spring 里你是在管理一个动画值的状态,然后把值绑定到元素的 style 上;Framer Motion 则是在声明组件的动画目标,transition 只是作为参数存在。对于这个简单例子,差别不大。可一旦交互复杂起来,你会感觉到思路的不同:React Spring 逼你把’值’当作一等公民去组合,Framer Motion 则鼓励你把’状态’直接放在 JSX 里。
真实项目里,哪些判断最容易出错
最容易踩的坑,就是误以为’物理动画’一定比’声明式动画’更流畅。流畅与否取决于动画帧率、元素数量、合成器优化,而不是模型本身。React Spring 的物理模拟并不保证高性能,Framer Motion 的 transform 优化也不代表所有动画都天然顺滑。两者都需要你注意避免强制同步布局,少改非 transform 属性。
第二个误区是认为 Framer Motion 只适合简单 UI。实际上它对手势、拖拽、布局动画有非常深入的支持,甚至可以用 useMotionValue 自己组合复杂链路。但它的设计目标是把 80% 的动画场景尽量简化,剩下 20% 才需要你深入底层。
第三个误区是把’选型’看成一次性决定。一个大型设计系统可能同时存在两套动画代码:标准交互用 Framer Motion,复杂数据联动用 React Spring。虽然这会带来多一套依赖的学习成本,但避免了用一个库的勉强写法去实现另一种场景的奇怪需求。
两个典型场景,怎么选更合适
一个中台项目里,表格筛选项变化后,卡片列表需要做重新排列动画。用 Framer Motion 的 layout 属性,你只需要确保每个卡片有稳定的 key,剩下的位移和淡入淡出它自动完成。而用 React Spring 你会发现自己要先算出每张卡片的位置变化量,再通过 useTransition 管理。相比之下,前者的开发效率高一个量级。
反过来,如果你要做一个可拖拽调参的曲线动画编辑器,每个控制点都需要跟随鼠标实时移动,同时其他曲线要平滑联动。React Spring 的 useSpring 加 interpolate 配置起来,要比 Framer Motion 里的 useMotionValue 组合直接得多。你不会想用声明式动画去描述一个随时变化的目标数组。
选型判断框架:先看场景,再看偏好
如果非要给一个结论,我的倾向是:如果你的核心诉求是产品 UI 的状态过渡、列表重排、弹窗进出场,选 Framer Motion;如果核心诉求是手势驱动的连续交互、实时数据绑定、多值联动,选 React Spring。这个结论不是来自框架崇拜,而是两种动画模型本身的适用范围。
下面的表格列出了我认为在选型时最重要的比较维度,供团队评估时参考。
| 维度 | React Spring | Framer Motion |
|---|---|---|
| 动画模型 | 弹簧物理模拟 | 声明式状态映射,内部支持弹簧和时间曲线 |
| 开发范式 | 把动画值作为可组合的数据流 | 把动画目标作为 JSX 属性 |
| 学习曲线 | 需要理解弹簧参数和值链 | 上手快,类型补全友好 |
| 典型场景 | 手势、拖拽、数据可视化、滚动联动 | UI 进入退出、布局动画、列表重排 |
| 包体积 | 相对精简 | 功能更全,体积更大 |
| React 状态亲和度 | 需要自己管理动画值 | 直接关联 React 状态,体验顺滑 |
| 复杂交互表达能力 | 更自由 | 够用但部分场景需要下钻变体 |
| 团队维护成本 | 偏工程思维,需要动画基础 | 新成员容易写出可维护的动画 |
这个表不是绝对的。如果你的团队已经有明确的动画规范,用 Framer Motion 的 variants 管理状态机,或者用 React Spring 的 useTransition 做复杂的列表动画,也都成立。关键是你在一个项目里要保持一致的抽象水平,不要一会用状态声明的思路,一会用值绑定的思路,否则后续维护会很难受。
落到具体项目,你可以用下面几个问题来收敛选择:
- 动画是产品交互的一部分,还是独立的数据可视化需求?前者更适合 Framer Motion,后者更适合 React Spring。
- 团队里有没有对动画原理理解较深的人?如果没有,Framer Motion 的默认配置和出错率都更低。
- 是否已经使用 Tailwind 或 Radix 这类只做基础 UI 的栈?如果动效需求非常集中,可以只引入体积更小的库。
- 是否需要支持复杂手势链(比如多指缩放、双击拖拽组合)?React Spring 配合 use-gesture 生态更成熟。
最后说一点工程上的长久考虑
动画库的选型,本质上是在评估你愿意付出多少抽象成本,以及你能得到多少表达能力。React Spring 给你更底层的数值控制,Framer Motion 给你更贴近产品状态的声明式体验。没有绝对的高下,只有与场景的契合度。
作为工程团队的负责人,我建议把动画库纳入到技术规范的统一审查里。先在 2-3 个项目里分别做小范围实验,再决定是否推广为标准。动画这种东西,代码可以重写,但用户体验一旦被割裂的风格影响,改起来就伤筋动骨。
无论最终选哪一个,都值得花时间理解它背后的动画模型。理解了弹簧参数,你才懂 Framer Motion 里 transition 的 stiffness 和 damping 在说什么;理解了声明式映射,你才明白为什么 React Spring 的 useSpring 能这么自然地融入数据流。技术选型是阶段性的,对动画本质的理解才是长期资产。
原创文章,作者:fudengji,如若转载,请注明出处:https://fudengji.cn/article/960/