lottie
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseLottie Animation Guidelines
Lottie动画实施指南
You are an expert in Lottie animations, web performance, and JavaScript. Follow these guidelines when implementing Lottie animations.
您是Lottie动画、网页性能和JavaScript方面的专家。在实现Lottie动画时,请遵循以下指南。
Core Principles
核心原则
Use dotLottie Format
使用dotLottie格式
- Prefer (dotLottie) format over
.lottie- up to 90% smaller file size.json - dotLottie bundles all assets (images, fonts) into a single compressed file
- Use the free dotLottie converter at lottiefiles.com
- 优先使用(dotLottie)格式而非
.lottie格式 - 文件大小最多可减小90%.json - dotLottie将所有资源(图片、字体)打包到单个压缩文件中
- 使用lottiefiles.com上的免费dotLottie转换器
Installation
安装
bash
undefinedbash
undefinedFor React
For React
npm install @lottiefiles/dotlottie-react
npm install @lottiefiles/dotlottie-react
For vanilla JS
For vanilla JS
npm install @lottiefiles/dotlottie-web
undefinednpm install @lottiefiles/dotlottie-web
undefinedReact Implementation
React实现
Basic Usage
基础用法
tsx
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
function Animation() {
return (
<DotLottieReact
src="/animations/loading.lottie"
loop
autoplay
/>
);
}tsx
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
function Animation() {
return (
<DotLottieReact
src="/animations/loading.lottie"
loop
autoplay
/>
);
}Control Animation Playback
控制动画播放
tsx
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
import { useState } from "react";
function ControlledAnimation() {
const [dotLottie, setDotLottie] = useState(null);
const dotLottieRefCallback = (dotLottie) => {
setDotLottie(dotLottie);
};
return (
<>
<DotLottieReact
src="/animation.lottie"
dotLottieRefCallback={dotLottieRefCallback}
/>
<button onClick={() => dotLottie?.play()}>Play</button>
<button onClick={() => dotLottie?.pause()}>Pause</button>
<button onClick={() => dotLottie?.stop()}>Stop</button>
</>
);
}tsx
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
import { useState } from "react";
function ControlledAnimation() {
const [dotLottie, setDotLottie] = useState(null);
const dotLottieRefCallback = (dotLottie) => {
setDotLottie(dotLottie);
};
return (
<>
<DotLottieReact
src="/animation.lottie"
dotLottieRefCallback={dotLottieRefCallback}
/>
<button onClick={() => dotLottie?.play()}>Play</button>
<button onClick={() => dotLottie?.pause()}>Pause</button>
<button onClick={() => dotLottie?.stop()}>Stop</button>
</>
);
}Performance Optimization
性能优化
Lazy Loading
懒加载
tsx
import { useEffect, useRef, useState } from "react";
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
function LazyLottie({ src }) {
const [isVisible, setIsVisible] = useState(false);
const containerRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.disconnect();
}
},
{ rootMargin: "100px" }
);
if (containerRef.current) {
observer.observe(containerRef.current);
}
return () => observer.disconnect();
}, []);
return (
<div ref={containerRef}>
{isVisible && <DotLottieReact src={src} autoplay loop />}
</div>
);
}tsx
import { useEffect, useRef, useState } from "react";
import { DotLottieReact } from "@lottiefiles/dotlottie-react";
function LazyLottie({ src }) {
const [isVisible, setIsVisible] = useState(false);
const containerRef = useRef(null);
useEffect(() => {
const observer = new IntersectionObserver(
([entry]) => {
if (entry.isIntersecting) {
setIsVisible(true);
observer.disconnect();
}
},
{ rootMargin: "100px" }
);
if (containerRef.current) {
observer.observe(containerRef.current);
}
return () => observer.disconnect();
}, []);
return (
<div ref={containerRef}>
{isVisible && <DotLottieReact src={src} autoplay loop />}
</div>
);
}Choose the Right Renderer
选择合适的渲染器
tsx
// SVG renderer - best quality, good for simple animations
<DotLottieReact src="/animation.lottie" renderer="svg" />
// Canvas renderer - better performance for complex animations
<DotLottieReact src="/animation.lottie" renderer="canvas" />
// Use canvas for:
// - Complex animations with many elements
// - Lower-powered devices
// - Animations with filters/effectstsx
// SVG渲染器 - 画质最佳,适合简单动画
<DotLottieReact src="/animation.lottie" renderer="svg" />
// Canvas渲染器 - 复杂动画性能更优
<DotLottieReact src="/animation.lottie" renderer="canvas" />
// 使用canvas的场景:
// - 包含大量元素的复杂动画
// - 性能较低的设备
// - 带有滤镜/特效的动画Reduce DOM Elements
减少DOM元素
- Reuse identical graphic elements in After Effects
- Simplify paths and reduce keyframes
- Avoid unnecessary layers
- Target under 1000 DOM elements per animation
- 在After Effects中复用相同的图形元素
- 简化路径并减少关键帧
- 避免不必要的图层
- 每个动画的DOM元素数量控制在1000个以内
Animation Design Best Practices
动画设计最佳实践
Avoid Performance-Heavy Features
避免使用性能消耗大的特性
AVOID:
- Masks (use alpha matte sparingly)
- Complex blur effects
- 3D layers
- Expressions
- Uncompressed images
- Large image assets
PREFER:
- Simple shapes (fills, strokes)
- Transform animations (position, scale, rotation)
- Opacity changes
- Path animations避免:
- 遮罩(尽量少用alpha遮罩)
- 复杂模糊效果
- 3D图层
- 表达式
- 未压缩图片
- 大尺寸图片资源
推荐:
- 简单形状(填充、描边)
- 变换动画(位置、缩放、旋转)
- 透明度变化
- 路径动画Optimize Images in Animations
优化动画中的图片
- Compress images to match display size
- If max display is 400x400, don't use 1000x1000 images
- Use vector graphics when possible
- Consider converting images to shapes- 根据显示尺寸压缩图片
- 如果最大显示尺寸为400x400,不要使用1000x1000的图片
- 尽可能使用矢量图形
- 考虑将图片转换为形状Interactivity
交互性
Cursor/Mouse Interaction
光标/鼠标交互
tsx
<DotLottieReact
src="/hover-animation.lottie"
playMode="hover"
/>tsx
<DotLottieReact
src="/hover-animation.lottie"
playMode="hover"
/>Scroll-Linked Animation
滚动联动动画
tsx
import { useScroll, useTransform } from "motion/react";
function ScrollLottie() {
const { scrollYProgress } = useScroll();
const [dotLottie, setDotLottie] = useState(null);
useEffect(() => {
if (!dotLottie) return;
const unsubscribe = scrollYProgress.on("change", (progress) => {
dotLottie.setFrame(progress * dotLottie.totalFrames);
});
return unsubscribe;
}, [dotLottie, scrollYProgress]);
return (
<DotLottieReact
src="/scroll-animation.lottie"
dotLottieRefCallback={setDotLottie}
autoplay={false}
/>
);
}tsx
import { useScroll, useTransform } from "motion/react";
function ScrollLottie() {
const { scrollYProgress } = useScroll();
const [dotLottie, setDotLottie] = useState(null);
useEffect(() => {
if (!dotLottie) return;
const unsubscribe = scrollYProgress.on("change", (progress) => {
dotLottie.setFrame(progress * dotLottie.totalFrames);
});
return unsubscribe;
}, [dotLottie, scrollYProgress]);
return (
<DotLottieReact
src="/scroll-animation.lottie"
dotLottieRefCallback={setDotLottie}
autoplay={false}
/>
);
}Segment Playback
分段播放
tsx
function SegmentAnimation() {
const [dotLottie, setDotLottie] = useState(null);
const playSegment = (start, end) => {
dotLottie?.setSegment(start, end);
dotLottie?.play();
};
return (
<>
<DotLottieReact
src="/multi-state.lottie"
dotLottieRefCallback={setDotLottie}
autoplay={false}
/>
<button onClick={() => playSegment(0, 30)}>State 1</button>
<button onClick={() => playSegment(30, 60)}>State 2</button>
</>
);
}tsx
function SegmentAnimation() {
const [dotLottie, setDotLottie] = useState(null);
const playSegment = (start, end) => {
dotLottie?.setSegment(start, end);
dotLottie?.play();
};
return (
<>
<DotLottieReact
src="/multi-state.lottie"
dotLottieRefCallback={setDotLottie}
autoplay={false}
/>
<button onClick={() => playSegment(0, 30)}>State 1</button>
<button onClick={() => playSegment(30, 60)}>State 2</button>
</>
);
}Accessibility
无障碍适配
Respect Reduced Motion
尊重减少动画偏好
tsx
function AccessibleAnimation() {
const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
if (prefersReducedMotion) {
return <img src="/static-fallback.svg" alt="Animation description" />;
}
return (
<DotLottieReact
src="/animation.lottie"
autoplay
loop
aria-label="Decorative loading animation"
/>
);
}tsx
function AccessibleAnimation() {
const prefersReducedMotion = window.matchMedia(
"(prefers-reduced-motion: reduce)"
).matches;
if (prefersReducedMotion) {
return <img src="/static-fallback.svg" alt="Animation description" />;
}
return (
<DotLottieReact
src="/animation.lottie"
autoplay
loop
aria-label="Decorative loading animation"
/>
);
}Provide Fallbacks
提供降级方案
tsx
function AnimationWithFallback() {
const [hasError, setHasError] = useState(false);
if (hasError) {
return <img src="/fallback.gif" alt="Animation" />;
}
return (
<DotLottieReact
src="/animation.lottie"
autoplay
onError={() => setHasError(true)}
/>
);
}tsx
function AnimationWithFallback() {
const [hasError, setHasError] = useState(false);
if (hasError) {
return <img src="/fallback.gif" alt="Animation" />;
}
return (
<DotLottieReact
src="/animation.lottie"
autoplay
onError={() => setHasError(true)}
/>
);
}Loading Strategy
加载策略
Use Preloader for Large Animations
为大型动画使用预加载器
tsx
function AnimationWithPreloader() {
const [isLoaded, setIsLoaded] = useState(false);
return (
<div className="animation-container">
{!isLoaded && (
<img src="/first-frame.webp" alt="" className="preloader" />
)}
<DotLottieReact
src="/large-animation.lottie"
onLoad={() => setIsLoaded(true)}
style={{ opacity: isLoaded ? 1 : 0 }}
autoplay
/>
</div>
);
}tsx
function AnimationWithPreloader() {
const [isLoaded, setIsLoaded] = useState(false);
return (
<div className="animation-container">
{!isLoaded && (
<img src="/first-frame.webp" alt="" className="preloader" />
)}
<DotLottieReact
src="/large-animation.lottie"
onLoad={() => setIsLoaded(true)}
style={{ opacity: isLoaded ? 1 : 0 }}
autoplay
/>
</div>
);
}File Size Guidelines
文件大小指南
| Animation Complexity | Target Size | Max DOM Elements |
|---|---|---|
| Simple icons | < 10KB | < 100 |
| UI animations | < 50KB | < 500 |
| Complex scenes | < 150KB | < 1500 |
| Hero animations | < 300KB | < 2500 |
| 动画复杂度 | 目标大小 | 最大DOM元素数量 |
|---|---|---|
| 简单图标 | < 10KB | < 100 |
| UI动画 | < 50KB | < 500 |
| 复杂场景 | < 150KB | < 1500 |
| 首页横幅动画 | < 300KB | < 2500 |
Cleanup
资源清理
Proper Cleanup in React
React中的正确清理
tsx
useEffect(() => {
return () => {
dotLottie?.destroy();
};
}, [dotLottie]);tsx
useEffect(() => {
return () => {
dotLottie?.destroy();
};
}, [dotLottie]);Best Practices Summary
最佳实践总结
- Use dotLottie format for smaller file sizes
- Lazy load animations not in viewport
- Use canvas renderer for complex animations
- Avoid masks, blurs, and expressions
- Compress and optimize image assets
- Respect reduced motion preferences
- Provide static fallbacks for errors
- Clean up animations on unmount
- Keep DOM element count low
- Use preloaders for large animations
- 使用dotLottie格式减小文件大小
- 对不在视口中的动画使用懒加载
- 对复杂动画使用canvas渲染器
- 避免使用遮罩、模糊和表达式
- 压缩并优化图片资源
- 尊重减少动画的用户偏好
- 为错误情况提供静态降级方案
- 在组件卸载时清理动画资源
- 控制DOM元素数量在较低水平
- 为大型动画使用预加载器