motion
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMotion Animation Guidelines
Motion动画指南
You are an expert in Motion (motion.dev), JavaScript, TypeScript, and web animation performance. Follow these guidelines when creating animations.
您是Motion(motion.dev)、JavaScript、TypeScript和Web动画性能方面的专家。创建动画时请遵循以下指南。
Core Principles
核心原则
About Motion
关于Motion
- Motion is the JavaScript animation library from the creator of Framer Motion
- Use for vanilla JavaScript/TypeScript projects
motion - Use for React projects (see framer-motion skill)
motion/react - Designed for high performance with minimal bundle size
- Motion是由Framer Motion开发者打造的JavaScript动画库
- 在原生JavaScript/TypeScript项目中使用
motion - 在React项目中使用(参考framer-motion相关内容)
motion/react - 专为高性能设计,包体积极小
Installation
安装
bash
npm install motionbash
npm install motionBasic Import
基础导入
javascript
import { animate, scroll, inView, timeline } from "motion";javascript
import { animate, scroll, inView, timeline } from "motion";Basic Animations
基础动画
Simple Animation
简单动画
javascript
import { animate } from "motion";
// Animate a single element
animate(".element", { x: 100, opacity: 1 }, { duration: 0.5 });
// Animate with options
animate(
".element",
{ transform: "translateX(100px)" },
{
duration: 0.8,
easing: "ease-out"
}
);javascript
import { animate } from "motion";
// 为单个元素添加动画
animate(".element", { x: 100, opacity: 1 }, { duration: 0.5 });
// 带配置项的动画
animate(
".element",
{ transform: "translateX(100px)" },
{
duration: 0.8,
easing: "ease-out"
}
);Keyframes
关键帧动画
javascript
animate(
".element",
{
x: [0, 100, 50], // Keyframe values
opacity: [0, 1, 0.5]
},
{ duration: 1 }
);javascript
animate(
".element",
{
x: [0, 100, 50], // 关键帧数值
opacity: [0, 1, 0.5]
},
{ duration: 1 }
);Performance Optimization
性能优化
Animate Transform Properties
优先动画变换属性
javascript
// Best performance - GPU accelerated
animate(".element", {
x: 100, // translateX
y: 50, // translateY
scale: 1.2, // scale
rotate: 45, // rotate
opacity: 0.5 // opacity
});
// Avoid when possible - triggers layout
animate(".element", {
width: 200, // Causes layout recalculation
height: 150, // Causes layout recalculation
top: 50, // Causes layout recalculation
left: 100 // Causes layout recalculation
});javascript
// 最佳性能 - GPU加速
animate(".element", {
x: 100, // translateX
y: 50, // translateY
scale: 1.2, // 缩放
rotate: 45, // 旋转
opacity: 0.5 // 透明度
});
// 尽可能避免 - 会触发重排
animate(".element", {
width: 200, // 会导致布局重计算
height: 150, // 会导致布局重计算
top: 50, // 会导致布局重计算
left: 100 // 会导致布局重计算
});Use will-change
使用will-change
javascript
// Add will-change for transform animations
const element = document.querySelector(".element");
element.style.willChange = "transform";
animate(element, { x: 100 }, {
onComplete: () => {
element.style.willChange = "auto"; // Remove after animation
}
});javascript
// 为变换动画添加will-change
const element = document.querySelector(".element");
element.style.willChange = "transform";
animate(element, { x: 100 }, {
onComplete: () => {
element.style.willChange = "auto"; // 动画结束后移除
}
});Hardware Acceleration
硬件加速
Motion automatically uses hardware-accelerated properties when possible. For best performance:
- Prefer ,
xovery,lefttop - Prefer over
scale,widthheight - Use for fade effects
opacity - Use over
rotatetransform: rotate()
Motion会在可能的情况下自动使用硬件加速属性。为获得最佳性能:
- 优先使用、
x而非y、lefttop - 优先使用而非
scale、widthheight - 使用实现淡入淡出效果
opacity - 使用而非
rotatetransform: rotate()
Timeline Animations
时间线动画
Create Timelines
创建时间线
javascript
import { timeline } from "motion";
const sequence = [
[".header", { y: ["-100%", 0], opacity: [0, 1] }],
[".content", { y: [50, 0], opacity: [0, 1] }, { at: "-0.3" }],
[".footer", { y: [50, 0], opacity: [0, 1] }, { at: "-0.3" }]
];
const controls = timeline(sequence, {
duration: 0.8,
defaultOptions: { easing: "ease-out" }
});javascript
import { timeline } from "motion";
const sequence = [
[".header", { y: ["-100%", 0], opacity: [0, 1] }],
[".content", { y: [50, 0], opacity: [0, 1] }, { at: "-0.3" }],
[".footer", { y: [50, 0], opacity: [0, 1] }, { at: "-0.3" }]
];
const controls = timeline(sequence, {
duration: 0.8,
defaultOptions: { easing: "ease-out" }
});Timeline Controls
时间线控制
javascript
const controls = timeline(sequence);
controls.play();
controls.pause();
controls.reverse();
controls.stop();
controls.finish();
// Seek to specific time
controls.currentTime = 0.5;javascript
const controls = timeline(sequence);
controls.play();
controls.pause();
controls.reverse();
controls.stop();
controls.finish();
// 跳转到指定时间点
controls.currentTime = 0.5;Scroll Animations
滚动动画
Basic Scroll Animation
基础滚动动画
javascript
import { scroll, animate } from "motion";
scroll(
animate(".progress-bar", { scaleX: [0, 1] }),
{ target: document.querySelector("article") }
);javascript
import { scroll, animate } from "motion";
scroll(
animate(".progress-bar", { scaleX: [0, 1] }),
{ target: document.querySelector("article") }
);Scroll-Linked Animation
滚动关联动画
javascript
scroll(({ y }) => {
// y.progress is 0 to 1
animate(".element", {
opacity: y.progress,
y: y.progress * 100
}, { duration: 0 });
});javascript
scroll(({ y }) => {
// y.progress取值范围0到1
animate(".element", {
opacity: y.progress,
y: y.progress * 100
}, { duration: 0 });
});Scroll with Container
容器内滚动动画
javascript
scroll(
animate(".parallax", { y: [0, -100] }),
{
target: document.querySelector(".section"),
offset: ["start end", "end start"]
}
);javascript
scroll(
animate(".parallax", { y: [0, -100] }),
{
target: document.querySelector(".section"),
offset: ["start end", "end start"]
}
);In-View Animations
视口触发动画
Trigger on Visibility
可见性触发
javascript
import { inView, animate } from "motion";
inView(".card", (info) => {
animate(info.target, { opacity: 1, y: 0 }, { duration: 0.5 });
// Return cleanup function
return () => {
animate(info.target, { opacity: 0, y: 20 }, { duration: 0.2 });
};
});javascript
import { inView, animate } from "motion";
inView(".card", (info) => {
animate(info.target, { opacity: 1, y: 0 }, { duration: 0.5 });
// 返回清理函数
return () => {
animate(info.target, { opacity: 0, y: 20 }, { duration: 0.2 });
};
});With Options
带配置项
javascript
inView(
".element",
(info) => {
animate(info.target, { scale: [0.8, 1], opacity: [0, 1] });
},
{
margin: "-100px", // Trigger 100px before entering viewport
amount: 0.5 // Trigger when 50% visible
}
);javascript
inView(
".element",
(info) => {
animate(info.target, { scale: [0.8, 1], opacity: [0, 1] });
},
{
margin: "-100px", // 进入视口前100px触发
amount: 0.5 // 元素50%可见时触发
}
);Stagger Animations
stagger动画(序列动画)
Stagger Multiple Elements
多元素 stagger 动画
javascript
import { stagger, animate } from "motion";
animate(
".list-item",
{ opacity: [0, 1], y: [20, 0] },
{ delay: stagger(0.1) }
);javascript
import { stagger, animate } from "motion";
animate(
".list-item",
{ opacity: [0, 1], y: [20, 0] },
{ delay: stagger(0.1) }
);Stagger from Center
从中心开始的 stagger 动画
javascript
animate(
".grid-item",
{ scale: [0, 1] },
{ delay: stagger(0.05, { from: "center" }) }
);javascript
animate(
".grid-item",
{ scale: [0, 1] },
{ delay: stagger(0.05, { from: "center" }) }
);Stagger with Easing
带缓动的 stagger 动画
javascript
animate(
".item",
{ x: ["-100%", 0] },
{
delay: stagger(0.1, {
easing: "ease-out",
start: 0.2
})
}
);javascript
animate(
".item",
{ x: ["-100%", 0] },
{
delay: stagger(0.1, {
easing: "ease-out",
start: 0.2
})
}
);Spring Animations
弹性动画
Use Springs for Natural Motion
使用弹性实现自然动效
javascript
animate(
".element",
{ scale: 1.2 },
{
easing: "spring",
// or with custom spring settings
easing: [0.34, 1.56, 0.64, 1] // Custom bezier curve
}
);javascript
animate(
".element",
{ scale: 1.2 },
{
easing: "spring",
// 或自定义弹性设置
easing: [0.34, 1.56, 0.64, 1] // 自定义贝塞尔曲线
}
);Spring Options
弹性配置项
javascript
animate(".element", { x: 100 }, {
type: "spring",
stiffness: 300,
damping: 30
});javascript
animate(".element", { x: 100 }, {
type: "spring",
stiffness: 300,
damping: 30
});Easing Functions
缓动函数
Built-in Easings
内置缓动
javascript
// Common easing values
animate(".element", { x: 100 }, { easing: "ease" });
animate(".element", { x: 100 }, { easing: "ease-in" });
animate(".element", { x: 100 }, { easing: "ease-out" });
animate(".element", { x: 100 }, { easing: "ease-in-out" });
animate(".element", { x: 100 }, { easing: "linear" });
// Cubic bezier
animate(".element", { x: 100 }, {
easing: [0.25, 0.1, 0.25, 1]
});javascript
// 常见缓动值
animate(".element", { x: 100 }, { easing: "ease" });
animate(".element", { x: 100 }, { easing: "ease-in" });
animate(".element", { x: 100 }, { easing: "ease-out" });
animate(".element", { x: 100 }, { easing: "ease-in-out" });
animate(".element", { x: 100 }, { easing: "linear" });
// 贝塞尔曲线
animate(".element", { x: 100 }, {
easing: [0.25, 0.1, 0.25, 1]
});Animation Controls
动画控制
Control Playback
播放控制
javascript
const controls = animate(".element", { x: 100 }, { duration: 1 });
// Control methods
controls.play();
controls.pause();
controls.stop();
controls.finish();
controls.reverse();
// Get/set time
controls.currentTime = 0.5;
console.log(controls.duration);
// Cancel animation
controls.cancel();javascript
const controls = animate(".element", { x: 100 }, { duration: 1 });
// 控制方法
controls.play();
controls.pause();
controls.stop();
controls.finish();
controls.reverse();
// 获取/设置时间
controls.currentTime = 0.5;
console.log(controls.duration);
// 取消动画
controls.cancel();Animation Events
动画事件
javascript
const controls = animate(
".element",
{ x: 100 },
{
duration: 1,
onComplete: () => console.log("Done!")
}
);
// Promise-based
controls.finished.then(() => {
console.log("Animation finished");
});javascript
const controls = animate(
".element",
{ x: 100 },
{
duration: 1,
onComplete: () => console.log("完成!")
}
);
// 基于Promise的方式
controls.finished.then(() => {
console.log("动画已完成");
});Accessibility
无障碍适配
Respect Reduced Motion
尊重减少动画偏好
javascript
const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
animate(
".element",
{ x: 100, opacity: 1 },
{
duration: prefersReducedMotion ? 0 : 0.5,
easing: prefersReducedMotion ? "linear" : "ease-out"
}
);javascript
const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
animate(
".element",
{ x: 100, opacity: 1 },
{
duration: prefersReducedMotion ? 0 : 0.5,
easing: prefersReducedMotion ? "linear" : "ease-out"
}
);Create Accessible Wrapper
创建无障碍封装函数
javascript
function safeAnimate(element, keyframes, options = {}) {
const reducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
return animate(element, keyframes, {
...options,
duration: reducedMotion ? 0 : (options.duration ?? 0.3)
});
}javascript
function safeAnimate(element, keyframes, options = {}) {
const reducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
return animate(element, keyframes, {
...options,
duration: reducedMotion ? 0 : (options.duration ?? 0.3)
});
}Integration with Frameworks
与框架集成
Vanilla JavaScript
原生JavaScript
javascript
document.addEventListener("DOMContentLoaded", () => {
animate(".hero", { opacity: [0, 1], y: [30, 0] });
});javascript
document.addEventListener("DOMContentLoaded", () => {
animate(".hero", { opacity: [0, 1], y: [30, 0] });
});With Event Listeners
结合事件监听器
javascript
const button = document.querySelector(".button");
button.addEventListener("mouseenter", () => {
animate(button, { scale: 1.05 }, { duration: 0.2 });
});
button.addEventListener("mouseleave", () => {
animate(button, { scale: 1 }, { duration: 0.2 });
});javascript
const button = document.querySelector(".button");
button.addEventListener("mouseenter", () => {
animate(button, { scale: 1.05 }, { duration: 0.2 });
});
button.addEventListener("mouseleave", () => {
animate(button, { scale: 1 }, { duration: 0.2 });
});Cleanup
清理工作
Cancel Animations
取消动画
javascript
const controls = animate(".element", { x: 100 });
// Later, cancel it
controls.cancel();javascript
const controls = animate(".element", { x: 100 });
// 之后取消动画
controls.cancel();Cleanup Pattern
清理模式
javascript
class AnimatedComponent {
constructor(element) {
this.element = element;
this.animations = [];
}
animate(keyframes, options) {
const controls = animate(this.element, keyframes, options);
this.animations.push(controls);
return controls;
}
destroy() {
this.animations.forEach(anim => anim.cancel());
this.animations = [];
}
}javascript
class AnimatedComponent {
constructor(element) {
this.element = element;
this.animations = [];
}
animate(keyframes, options) {
const controls = animate(this.element, keyframes, options);
this.animations.push(controls);
return controls;
}
destroy() {
this.animations.forEach(anim => anim.cancel());
this.animations = [];
}
}Best Practices Summary
最佳实践总结
- Use transform properties (x, y, scale, rotate) for best performance
- Add will-change before complex animations, remove after
- Use timeline for sequenced animations
- Use scroll() for scroll-linked effects
- Use inView() for viewport-triggered animations
- Use stagger() for animating multiple elements
- Prefer springs for interactive/gesture animations
- Always respect reduced motion preferences
- Cancel animations when no longer needed
- Test performance on actual devices
- 使用变换属性(x、y、scale、rotate)以获得最佳性能
- 复杂动画前添加will-change,动画结束后移除
- 使用时间线实现序列动画
- 使用scroll()实现滚动关联效果
- 使用inView()实现视口触发动画
- 使用stagger()实现多元素序列动画
- 交互/手势动画优先使用弹性效果
- 始终尊重减少动画的用户偏好
- 不再需要时及时取消动画
- 在真实设备上测试性能