如何在 Web 项目里稳定集成 Lottie 动画?
Web 项目里接 Lottie,看起来只是引入一个 JSON,实际要同时处理加载、渲染器、生命周期、降级和性能。很多页面一开始播放很顺,等营销活动上线、多个动画同时进首屏,就会出现掉帧、内存泄漏或移动端白屏。比较稳的做法是:先确定动画用途,再选接入方式,最后把播放控制和销毁逻辑写进组件生命周期里。
先选接入方式
如果只是运营页放一个循环动画,<lottie-player> 上手最快,HTML 里声明 src、loop、autoplay 就能跑,适合低代码页面或非复杂交互。缺点是可控性有限,深度定制和精细事件管理不如直接用 lottie-web。React、Vue、Angular 项目里,如果动画要和按钮点击、滚动进度、表单状态联动,建议直接封装 lottie-web;这样能拿到实例,控制 play、pause、stop、goToAndStop、setSpeed 和 destroy。
安装时用 npm 包比直接挂 CDN 更可控,版本也能锁住。动画 JSON 可以放 public 目录走 URL,也可以作为模块 import 进来。前者适合大文件和 CDN 缓存,后者适合小动画、构建时一起校验;边界是不要把很多大型 JSON 全部打进首屏 bundle,否则还没播放动画,页面 JS 就先变重了。
jsximport { useEffect, useRef } from 'react' import lottie from 'lottie-web' export function LottieBox({ path, loop = true }) { const el = useRef(null) useEffect(() => { if (!el.current) return const anim = lottie.loadAnimation({ container: el.current, renderer: 'svg', loop, autoplay: true, path }) return () => anim.destroy() }, [path, loop]) return <div ref={el} aria-hidden="true" /> }
渲染器不是随便选
lottie-web 常见渲染器有 svg、canvas 和 html。SVG 清晰、可缩放、方便调试,也适合图层不太多的图标和插画动画;Canvas 对大量元素或频繁变化更友好,但不如 SVG 容易被 CSS 精细控制。HTML 渲染器使用场景较少,除非你明确知道它解决了什么问题,否则不要默认选它。
如果动画需要响应式尺寸,容器用 CSS 控制宽高,实例创建后在 resize 时调用 animation.resize()。如果页面里有多个 Lottie,别让它们全部 autoplay;进入视口再加载,离开视口暂停,通常比事后抱怨“Lottie 性能差”有效得多。对于装饰动画,还要考虑 prefers-reduced-motion,用户系统设置减少动态效果时,应停用自动播放或改成静态图。
jsconst reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches const observer = new IntersectionObserver(([entry]) => { if (entry.isIntersecting && !reduceMotion) animation.play() else animation.pause() }) observer.observe(container)
加载失败和降级要提前设计
线上最常见的问题不是 API 不会用,而是 JSON 路径 404、跨域配置缺失、图片资源没一起上传、组件卸载后实例还在跑。接入时至少监听 data_failed,并给容器准备一张静态 fallback。动画文件走 CDN 时,缓存时间可以长一点,但文件名最好带 hash;如果同名文件被替换,用户本地缓存旧 JSON,前端代码却按新结构控制帧,问题会很隐蔽。
颜色和文案动态修改也要克制。直接改 JSON 内部结构可以做到,但它依赖 AE 导出的层级和 keypath,一旦设计师重命名图层就会失效。更稳的方式是把需要变体的动画提前拆好,或约定图层命名规范,再用测试覆盖关键路径。
追问
用 lottie-web 还是 LottieFiles Player 更好?
如果只是展示动画,LottieFiles Player 简洁,交给内容同学维护也方便。需要和业务状态联动时,lottie-web 更合适,因为实例 API 更直接,生命周期也更可控。取舍点是开发成本和控制能力:越靠近业务逻辑,越不该把控制权藏在 Web Component 里。踩坑是先用 Player 快速上线,后面要按滚动进度控制帧,结果又重写一遍。
SVG 和 Canvas 渲染器怎么选?
SVG 适合小型、清晰、可缩放的动效,比如图标、空状态、按钮反馈。Canvas 更适合图层多、变化频繁的动画,但它不方便逐个节点用 CSS 控制,也要注意高清屏缩放。边界是不要凭感觉选,拿同一份 JSON 在目标机型上测 FPS 和内存。常见坑是桌面浏览器 SVG 很顺,低端 Android 同时播放三个后就明显卡顿。
Lottie 动画应该打进 bundle 还是放 CDN?
小而关键的动画可以随包引入,构建能发现 JSON 是否存在,离线体验也更简单。大文件、运营素材和可替换动画更适合放 CDN,通过 path 加载并设置缓存。取舍在首屏体积和发布灵活性之间:bundle 稳但重,CDN 灵活但要处理网络失败。踩坑是把十几个活动动画 import 到首页,用户还没看到它们就先下载了几 MB 的 JS。
组件卸载时为什么一定要 destroy?
Lottie 实例会持有 DOM、定时器、事件监听和渲染状态,单页应用路由切换后如果不销毁,内存会慢慢涨。暂停只能停播放,不等于释放资源;真正离开页面或组件时应该调用 destroy()。边界是弹窗临时隐藏可以 pause,组件永久卸载才 destroy。很多“页面越用越卡”的问题,最后都能追到没有清理动画实例。
怎么给不支持或不想看动画的用户降级?
最简单的降级是一张同尺寸静态图,加载失败、减少动态效果、低性能设备都可以显示它。复杂业务也可以降级成 CSS transition,但不要为了还原 Lottie 再写一套复杂动画。取舍是体验一致性和维护成本:静态图不酷,但稳定、便宜、可预测。踩坑是只在网速好、设备新的环境测试,线上遇到弱网时容器空白,用户以为页面没加载完。