framer-motion-magic
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseFramer Motion Magic ✨
Framer Motion 魔法 ✨
Production-ready animation patterns for stunning React UIs.
可用于生产环境的动画模式,打造惊艳的React用户界面。
1. Core Concepts
1. 核心概念
motion Components
motion 组件
| Element | Usage |
|---|---|
| Animated div container |
| Interactive button |
| SVG animations |
| Wrap custom components |
| 元素 | 用途 |
|---|---|
| 带动画的div容器 |
| 交互式按钮 |
| SVG动画 |
| 包裹自定义组件 |
Animation Properties
动画属性
| Prop | Purpose |
|---|---|
| Starting state (string or object) |
| Target state to animate to |
| State when unmounting (needs AnimatePresence) |
| Timing, easing, spring config |
| Named animation states |
| 属性 | 作用 |
|---|---|
| 初始状态(字符串或对象) |
| 动画目标状态 |
| 卸载时的状态(需要AnimatePresence) |
| 时长、缓动、弹簧配置 |
| 命名动画状态 |
Transition Types
过渡类型
| Type | When to Use |
|---|---|
| Natural, bouncy feel (default) |
| Precise timing control |
| Momentum-based (drag) |
tsx
// Spring (natural motion)
transition={{ type: "spring", stiffness: 300, damping: 20 }}
// Tween (precise)
transition={{ type: "tween", duration: 0.3, ease: "easeInOut" }}| 类型 | 适用场景 |
|---|---|
| 自然弹性效果(默认) |
| 精确时长控制 |
| 基于动量的效果(拖拽) |
tsx
// Spring (natural motion)
transition={{ type: "spring", stiffness: 300, damping: 20 }}
// Tween (precise)
transition={{ type: "tween", duration: 0.3, ease: "easeInOut" }}2. Essential Patterns
2. 核心动画模式
Fade In
淡入效果
tsx
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.3 }}
>
Content
</motion.div>tsx
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.3 }}
>
Content
</motion.div>Slide Up with Fade
上滑淡入
tsx
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, ease: "easeOut" }}
>
Content
</motion.div>tsx
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, ease: "easeOut" }}
>
Content
</motion.div>Scale on Hover
悬停缩放
tsx
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
transition={{ type: "spring", stiffness: 400, damping: 17 }}
>
Click me
</motion.button>tsx
<motion.button
whileHover={{ scale: 1.05 }}
whileTap={{ scale: 0.95 }}
transition={{ type: "spring", stiffness: 400, damping: 17 }}
>
Click me
</motion.button>Stagger Children
子元素 stagger 动画
tsx
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { staggerChildren: 0.1 }
}
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
};
<motion.ul variants={containerVariants} initial="hidden" animate="visible">
{items.map(item => (
<motion.li key={item.id} variants={itemVariants}>
{item.name}
</motion.li>
))}
</motion.ul>tsx
const containerVariants = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { staggerChildren: 0.1 }
}
};
const itemVariants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
};
<motion.ul variants={containerVariants} initial="hidden" animate="visible">
{items.map(item => (
<motion.li key={item.id} variants={itemVariants}>
{item.name}
</motion.li>
))}
</motion.ul>3. AnimatePresence (Mount/Unmount)
3. AnimatePresence(挂载/卸载动画)
Basic Exit Animation
基础退出动画
tsx
import { AnimatePresence, motion } from "framer-motion";
<AnimatePresence>
{isVisible && (
<motion.div
key="modal"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
Modal content
</motion.div>
)}
</AnimatePresence>tsx
import { AnimatePresence, motion } from "framer-motion";
<AnimatePresence>
{isVisible && (
<motion.div
key="modal"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
Modal content
</motion.div>
)}
</AnimatePresence>Mode Options
模式选项
| Mode | Behavior |
|---|---|
| Enter/exit simultaneously (default) |
| Wait for exit before enter |
| Pop exiting element from layout flow |
| 模式 | 行为 |
|---|---|
| 进入/退出同时进行(默认) |
| 等待退出完成后再进入 |
| 将退出元素从布局流中移除 |
Page Transitions (Next.js)
页面过渡(Next.js)
tsx
// In _app.tsx or layout.tsx
<AnimatePresence mode="wait" initial={false}>
<motion.div
key={router.pathname}
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
transition={{ duration: 0.3 }}
>
<Component {...pageProps} />
</motion.div>
</AnimatePresence>tsx
// In _app.tsx or layout.tsx
<AnimatePresence mode="wait" initial={false}>
<motion.div
key={router.pathname}
initial={{ opacity: 0, x: 20 }}
animate={{ opacity: 1, x: 0 }}
exit={{ opacity: 0, x: -20 }}
transition={{ duration: 0.3 }}
>
<Component {...pageProps} />
</motion.div>
</AnimatePresence>4. Gesture Animations
4. 手势动画
Interactive Props
交互属性
| Prop | Trigger |
|---|---|
| Mouse enter |
| Mouse down / touch |
| Element focused |
| During drag |
| Element in viewport |
| 属性 | 触发条件 |
|---|---|
| 鼠标进入 |
| 鼠标按下/触摸 |
| 元素获得焦点 |
| 拖拽过程中 |
| 元素进入视口 |
Drag
拖拽效果
tsx
<motion.div
drag
dragConstraints={{ left: -100, right: 100, top: -50, bottom: 50 }}
dragElastic={0.2}
whileDrag={{ scale: 1.1 }}
/>tsx
<motion.div
drag
dragConstraints={{ left: -100, right: 100, top: -50, bottom: 50 }}
dragElastic={0.2}
whileDrag={{ scale: 1.1 }}
/>Drag with useDragControls
使用useDragControls的拖拽
tsx
const controls = useDragControls();
<div onPointerDown={(e) => controls.start(e)}>
Drag handle
</div>
<motion.div drag="x" dragControls={controls}>
Draggable content
</motion.div>tsx
const controls = useDragControls();
<div onPointerDown={(e) => controls.start(e)}>
Drag handle
</div>
<motion.div drag="x" dragControls={controls}>
Draggable content
</motion.div>5. Scroll Animations
5. 滚动动画
whileInView (Simple)
whileInView(简易版)
tsx
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.5 }}
>
Animates when scrolled into view
</motion.div>tsx
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
transition={{ duration: 0.5 }}
>
Animates when scrolled into view
</motion.div>useScroll Hook
useScroll 钩子
tsx
const { scrollYProgress } = useScroll();
// Animate based on scroll
<motion.div style={{ scaleX: scrollYProgress }} />tsx
const { scrollYProgress } = useScroll();
// Animate based on scroll
<motion.div style={{ scaleX: scrollYProgress }} />Scroll-Linked Parallax
滚动联动视差
tsx
const { scrollYProgress } = useScroll();
const y = useTransform(scrollYProgress, [0, 1], [0, -200]);
<motion.div style={{ y }}>
Parallax content
</motion.div>tsx
const { scrollYProgress } = useScroll();
const y = useTransform(scrollYProgress, [0, 1], [0, -200]);
<motion.div style={{ y }}>
Parallax content
</motion.div>6. Motion Hooks
6. 动效钩子
useMotionValue
useMotionValue
tsx
const x = useMotionValue(0);
<motion.div style={{ x }} drag="x" />tsx
const x = useMotionValue(0);
<motion.div style={{ x }} drag="x" />useTransform
useTransform
tsx
const x = useMotionValue(0);
const opacity = useTransform(x, [-100, 0, 100], [0, 1, 0]);
const background = useTransform(
x,
[-100, 0, 100],
["#ff0000", "#ffffff", "#00ff00"]
);tsx
const x = useMotionValue(0);
const opacity = useTransform(x, [-100, 0, 100], [0, 1, 0]);
const background = useTransform(
x,
[-100, 0, 100],
["#ff0000", "#ffffff", "#00ff00"]
);useSpring
useSpring
tsx
const x = useMotionValue(0);
const springX = useSpring(x, { stiffness: 300, damping: 30 });tsx
const x = useMotionValue(0);
const springX = useSpring(x, { stiffness: 300, damping: 30 });useVelocity
useVelocity
tsx
const x = useMotionValue(0);
const velocityX = useVelocity(x);
const scale = useTransform(velocityX, [-500, 0, 500], [0.8, 1, 0.8]);tsx
const x = useMotionValue(0);
const velocityX = useVelocity(x);
const scale = useTransform(velocityX, [-500, 0, 500], [0.8, 1, 0.8]);useInView
useInView
tsx
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
<motion.div
ref={ref}
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : {}}
/>tsx
const ref = useRef(null);
const isInView = useInView(ref, { once: true });
<motion.div
ref={ref}
initial={{ opacity: 0 }}
animate={isInView ? { opacity: 1 } : {}}
/>7. Layout Animations
7. 布局动画
Auto Layout
自动布局动画
tsx
<motion.div layout>
{/* Size/position changes animate automatically */}
</motion.div>tsx
<motion.div layout>
{/* Size/position changes animate automatically */}
</motion.div>Layout ID (Shared Element)
Layout ID(共享元素动画)
tsx
// Card in list
<motion.div layoutId={`card-${id}`}>
<h2>{title}</h2>
</motion.div>
// Expanded card (same layoutId)
<motion.div layoutId={`card-${id}`}>
<h2>{title}</h2>
<p>{description}</p>
</motion.div>tsx
// Card in list
<motion.div layoutId={`card-${id}`}>
<h2>{title}</h2>
</motion.div>
// Expanded card (same layoutId)
<motion.div layoutId={`card-${id}`}>
<h2>{title}</h2>
<p>{description}</p>
</motion.div>Layout Types
布局类型
| Value | Animates |
|---|---|
| Size + position |
| Only position |
| Only size |
| 值 | 动画范围 |
|---|---|
| 尺寸 + 位置 |
| 仅位置 |
| 仅尺寸 |
8. Variants System
8. Variants 系统
Defining Variants
定义Variants
tsx
const cardVariants = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
hover: { scale: 1.02, boxShadow: "0 10px 30px rgba(0,0,0,0.2)" },
tap: { scale: 0.98 },
exit: { opacity: 0, y: -20 }
};
<motion.div
variants={cardVariants}
initial="initial"
animate="animate"
whileHover="hover"
whileTap="tap"
exit="exit"
/>tsx
const cardVariants = {
initial: { opacity: 0, y: 20 },
animate: { opacity: 1, y: 0 },
hover: { scale: 1.02, boxShadow: "0 10px 30px rgba(0,0,0,0.2)" },
tap: { scale: 0.98 },
exit: { opacity: 0, y: -20 }
};
<motion.div
variants={cardVariants}
initial="initial"
animate="animate"
whileHover="hover"
whileTap="tap"
exit="exit"
/>Orchestration
动画编排
tsx
const containerVariants = {
hidden: {},
visible: {
transition: {
staggerChildren: 0.1,
delayChildren: 0.3
}
}
};
const itemVariants = {
hidden: { opacity: 0, x: -20 },
visible: { opacity: 1, x: 0 }
};tsx
const containerVariants = {
hidden: {},
visible: {
transition: {
staggerChildren: 0.1,
delayChildren: 0.3
}
}
};
const itemVariants = {
hidden: { opacity: 0, x: -20 },
visible: { opacity: 1, x: 0 }
};9. Performance Optimization
9. 性能优化
GPU-Accelerated Properties
GPU加速属性
| ✅ Use | ❌ Avoid |
|---|---|
| |
| |
|
| ✅ 推荐使用 | ❌ 避免使用 |
|---|---|
| |
| |
|
Performance Tips
性能优化技巧
| Tip | Implementation |
|---|---|
| Use transform over layout properties | |
| Avoid onUpdate callback | Triggers every frame |
| Use layout prop sparingly | Can cause reflows |
| Lazy load with useInView | Animate only when visible |
| Don't animate too many elements | Limit to 10-20 simultaneous |
| 技巧 | 实现方式 |
|---|---|
| 使用transform替代布局属性 | 用 |
| 避免onUpdate回调 | 会逐帧触发 |
| 谨慎使用layout属性 | 可能导致重排 |
| 结合useInView懒加载 | 仅在元素可见时执行动画 |
| 控制同时动画的元素数量 | 限制在10-20个以内 |
Hardware Acceleration Warning
硬件加速警告
These patterns may disable GPU acceleration:
tsx
// ❌ Avoid
<motion.div onUpdate={(latest) => console.log(latest)} />
<motion.div style={{ x: motionValue }} /> // MotionValue in style
transition={{ repeatDelay: 1 }} // repeatDelay
transition={{ damping: 0 }} // Zero damping以下模式可能会禁用GPU加速:
tsx
// ❌ Avoid
<motion.div onUpdate={(latest) => console.log(latest)} />
<motion.div style={{ x: motionValue }} /> // MotionValue in style
transition={{ repeatDelay: 1 }} // repeatDelay
transition={{ damping: 0 }} // Zero damping10. Accessibility
10. 无障碍设计
Respect Reduced Motion
尊重减少动效偏好
tsx
// Option 1: MotionConfig (Recommended)
<MotionConfig reducedMotion="user">
<App />
</MotionConfig>
// Option 2: useReducedMotion hook
const shouldReduce = useReducedMotion();
<motion.div
animate={shouldReduce ? { opacity: 1 } : { opacity: 1, y: 0 }}
/>tsx
// Option 1: MotionConfig (Recommended)
<MotionConfig reducedMotion="user">
<App />
</MotionConfig>
// Option 2: useReducedMotion hook
const shouldReduce = useReducedMotion();
<motion.div
animate={shouldReduce ? { opacity: 1 } : { opacity: 1, y: 0 }}
/>MotionConfig Options
MotionConfig选项
| Value | Behavior |
|---|---|
| Respect OS preference |
| Always reduce motion |
| Ignore preference |
| 值 | 行为 |
|---|---|
| 遵循系统偏好设置 |
| 始终减少动效 |
| 忽略偏好设置 |
What Gets Disabled
禁用的动效类型
When reduced motion is active:
- ✅ still animates
opacity - ✅ still animates
backgroundColor - ❌ (x, y, scale, rotate) - instant
transform - ❌ Layout animations - instant
当启用减少动效时:
- ✅ 仍会执行动画
opacity - ✅ 仍会执行动画
backgroundColor - ❌ (x, y, scale, rotate) - 立即生效
transform - ❌ 布局动画 - 立即生效
11. Common Patterns Reference
11. 常见模式参考
For detailed implementations with full code examples:
- Page Transitions: See references/page-transitions.md
- Modal/Dialog: See references/modal-patterns.md
- List Animations: See references/list-patterns.md
- Micro-interactions: See references/micro-interactions.md
如需完整代码示例的详细实现:
- 页面过渡: 查看 references/page-transitions.md
- 模态框/对话框: 查看 references/modal-patterns.md
- 列表动画: 查看 references/list-patterns.md
- 微交互: 查看 references/micro-interactions.md
12. Quick Reference
12. 速查手册
Easing Functions
缓动函数
| Name | Feel |
|---|---|
| Slow start |
| Slow end (most natural) |
| Slow both ends |
| Constant speed |
| Pull back then forward |
| Overshoot effect |
| 名称 | 效果 |
|---|---|
| 慢启动 |
| 慢结束(最自然) |
| 两端慢 |
| 匀速 |
| 先回拉再前进 |
| 过冲效果 |
Spring Presets
弹簧预设
| Feel | Config |
|---|---|
| Snappy | |
| Bouncy | |
| Smooth | |
| Gentle | |
| 效果 | 配置 |
|---|---|
| 轻快 | |
| 弹跳 | |
| 平滑 | |
| 柔和 | |
Duration Guidelines
时长指南
| Animation Type | Duration |
|---|---|
| Micro-interactions | 100-200ms |
| UI feedback | 200-300ms |
| Transitions | 300-500ms |
| Page transitions | 400-600ms |
| Complex sequences | 500-1000ms |
Remember: Animations should enhance UX, not distract. Use motion purposefully to guide attention, provide feedback, and create delight.
| 动画类型 | 时长 |
|---|---|
| 微交互 | 100-200ms |
| UI反馈 | 200-300ms |
| 过渡效果 | 300-500ms |
| 页面过渡 | 400-600ms |
| 复杂序列 | 500-1000ms |
记住: 动画应增强用户体验,而非分散注意力。要有目的性地使用动效,引导注意力、提供反馈并创造愉悦感。