GSAP 性能优化 是做什么的?
何时使用此技能
在优化 GSAP 动画以实现流畅 60fps、减少布局/绘制成本,或用户询问性能、卡顿或快速动画最佳实践时应用。
相关技能: 使用 gsap-core(变换、autoAlpha)和 gsap-timeline 构建动画;ScrollTrigger 性能问题请参阅 gsap-scrolltrigger。
优先使用 Transform 和 Opacity
动画化 transform(x、y、scaleX、scaleY、rotation、rotationX、rotationY、skewX、skewY)和 opacity 可将工作保留在合成器线程中,避免布局和大多数绘制。当变换可以实现相同效果时,避免动画化布局密集型属性。
- ✅ 优先使用:x、y、scale、rotation、opacity。
- ❌ 尽可能避免:width、height、top、left、margin、padding(它们会触发布局并可能导致卡顿)。
GSAP 的 x 和 y 默认使用变换(translate);优先使用它们代替 left/top 来实现移动效果。
will-change
在将进行动画化的元素的 CSS 中使用 will-change。这会给浏览器提示以提升该层。
will-change: transform;
批处理读取与写入
GSAP 内部会批处理更新。当将 GSAP 与直接 DOM 读取/写入或依赖布局的代码混合使用时,避免以导致重复布局抖动的方式交错读取和写入。优先先执行所有读取,再执行所有写入(或让 GSAP 一次性处理写入)。
大量元素(Stagger、列表)
- 当动画相同时,使用 stagger 而不是许多带有手动延迟的独立补间;这更高效。
- 对于长列表,考虑使用虚拟化或仅动画化可见元素;避免在可能导致卡顿的情况下创建数百个同时进行的补间。
- 尽可能重用时间线;避免每一帧都创建新时间线。
频繁更新的属性(例如鼠标跟随器)
对于频繁更新的属性(例如鼠标跟随器的 x/y),优先使用 gsap.quickTo()。它重用单个补间,而不是在每次更新时创建新补间。
let xTo = gsap.quickTo("#id", "x", { duration: 0.4, ease: "power3" }),
yTo = gsap.quickTo("#id", "y", { duration: 0.4, ease: "power3" });
document.querySelector("#container").addEventListener("mousemove", (e) => {
xTo(e.pageX);
yTo(e.pageY);
});
ScrollTrigger 与性能
- pin: true 会提升被固定元素;只固定必要的内容。
- scrub 使用小值(例如
scrub: 1)可以减少滚动过程中的工作;在低端设备上测试。 - 仅在布局实际发生变化时(例如内容加载后)调用 ScrollTrigger.refresh(),而不是每次调整大小时都调用;尽可能进行防抖。
减少同时进行的工作
- 当动画不在视口内时(例如用户导航离开时),暂停或销毁屏幕外或非活动的动画。
- 避免同时在众多元素上动画化大量属性;如有需要,简化或排序。
最佳实践
- ✅ 动画化 transform 和 opacity;仅在将要进行动画化的元素上使用 will-change 的 CSS。
- ✅ 当动画相同时,使用 stagger 代替许多带有手动延迟的独立补间。
- ✅ 对于频繁更新的属性(例如鼠标跟随器),使用 gsap.quickTo()。
- ✅ 清理或销毁屏幕外动画;当布局发生变化时调用 ScrollTrigger.refresh(),尽可能进行防抖。
不要做的事
- ❌ 当 x/y/scale 可以实现相同外观时,使用 width/height/top/left 来实现移动效果。
- ❌ “以防万一”地对每个元素设置 will-change 或 force3D;只对实际进行动画化的元素使用。
- ❌ 创建数百个重叠的补间或 ScrollTrigger,而不在低端设备上进行测试。
- ❌ 忽视清理;残留的补间和 ScrollTrigger 会持续运行,损害性能和正确性。