GSAP 性能优化
GSAP 性能优化技巧,确保动画流畅运行在 60fps。
📚 性能优化原则
60fps 目标
- 帧率:60fps = 每帧 16.67ms
- 目标:保持动画流畅,避免卡顿
- 监控:使用浏览器 DevTools 监控性能
性能影响因素
- 属性选择:transform 和 opacity 性能最好
- 动画数量:同时运行的动画数量
- 元素数量:动画元素的数量
- 重排重绘:避免触发布局和绘制
🎯 属性优化
GPU 加速属性
✅ 推荐使用:这些属性由 GPU 处理,性能最佳
// Transform 属性
gsap.to(".box", {
x: 100, // translateX
y: 50, // translateY
z: 0, // translateZ
rotation: 360, // rotateZ
rotationX: 180, // rotateX
rotationY: 90, // rotateY
scale: 1.5, // scale
scaleX: 2, // scaleX
scaleY: 0.5, // scaleY
skewX: 45, // skewX
skewY: 30, // skewY
opacity: 0.5 // opacity
});触发重排的属性
❌ 避免使用:这些属性会触发重排,性能较差
// ❌ 不推荐
gsap.to(".box", {
left: "100px", // 触发重排
top: "50px", // 触发重排
width: "200px", // 触发重排
height: "100px", // 触发重排
margin: "20px", // 触发重排
padding: "10px" // 触发重排
});
// ✅ 推荐:使用 transform
gsap.to(".box", {
x: 100, // translateX
y: 50 // translateY
});颜色和滤镜
⚠️ 谨慎使用:这些属性可能触发重绘
// 颜色动画(需要 ColorPropsPlugin)
gsap.to(".box", {
backgroundColor: "#ff0000",
color: "#ffffff"
});
// 滤镜动画(性能较差)
gsap.to(".box", {
filter: "blur(10px)",
backdropFilter: "blur(10px)"
});🎨 will-change 优化
使用 will-change
.animated-element {
will-change: transform, opacity;
}动态设置 will-change
// 动画开始前
gsap.set(".box", { willChange: "transform" });
// 动画完成后移除
gsap.to(".box", {
x: 100,
duration: 1,
onComplete: function() {
gsap.set(".box", { willChange: "auto" });
}
});🚀 批量操作优化
使用 Timeline 而不是多个独立动画
// ❌ 不推荐:多个独立动画
gsap.to(".box1", { x: 100, duration: 1 });
gsap.to(".box2", { y: 100, duration: 1 });
gsap.to(".box3", { rotation: 360, duration: 1 });
// ✅ 推荐:使用 Timeline
const tl = gsap.timeline();
tl.to(".box1", { x: 100, duration: 1 })
.to(".box2", { y: 100, duration: 1 })
.to(".box3", { rotation: 360, duration: 1 });使用 stagger 批量动画
// ✅ 推荐:使用 stagger
gsap.to(".item", {
x: 100,
duration: 1,
stagger: 0.1
});
// ❌ 不推荐:循环创建多个动画
document.querySelectorAll(".item").forEach((item, i) => {
gsap.to(item, {
x: 100,
duration: 1,
delay: i * 0.1
});
});📊 性能监控
使用 DevTools 监控
- Performance 面板:录制动画性能
- Rendering 面板:显示重排重绘
- FPS 计数器:监控帧率
代码性能监控
// 监控动画性能
const startTime = performance.now();
gsap.to(".box", {
x: 100,
duration: 1,
onComplete: function() {
const endTime = performance.now();
console.log(`动画耗时: ${endTime - startTime}ms`);
}
});使用 requestAnimationFrame
let frameCount = 0;
let lastTime = performance.now();
function measureFPS() {
frameCount++;
const currentTime = performance.now();
if (currentTime >= lastTime + 1000) {
console.log(`FPS: ${frameCount}`);
frameCount = 0;
lastTime = currentTime;
}
requestAnimationFrame(measureFPS);
}
measureFPS();🎯 ScrollTrigger 性能优化
减少 ScrollTrigger 数量
// ❌ 不推荐:为每个元素创建 ScrollTrigger
elements.forEach(element => {
gsap.from(element, {
scrollTrigger: {
trigger: element,
start: "top 80%"
}
});
});
// ✅ 推荐:批量处理
gsap.utils.toArray(".item").forEach((item, i) => {
gsap.from(item, {
y: 50,
opacity: 0,
duration: 0.5,
scrollTrigger: {
trigger: item,
start: "top 80%",
toggleActions: "play none none reverse"
},
delay: i * 0.1
});
});使用 markers 调试后移除
// 开发时使用
scrollTrigger: {
trigger: ".box",
start: "top center",
markers: true // 调试时使用
}
// 生产环境移除
scrollTrigger: {
trigger: ".box",
start: "top center",
markers: false // 生产环境关闭
}及时刷新和清理
// 窗口大小改变时刷新
window.addEventListener("resize", () => {
ScrollTrigger.refresh();
});
// 组件卸载时清理
function cleanup() {
ScrollTrigger.getAll().forEach(st => st.kill());
}💡 优化技巧
1. 减少同时运行的动画
// ✅ 推荐:使用 Timeline 控制动画数量
const tl = gsap.timeline();
tl.to(".box1", { x: 100 })
.to(".box2", { y: 100 })
.to(".box3", { rotation: 360 });
// ❌ 不推荐:同时运行太多动画
for (let i = 0; i < 100; i++) {
gsap.to(`.box${i}`, { x: 100 });
}2. 使用对象引用而不是选择器
// ✅ 推荐:性能更好
const box = document.querySelector(".box");
gsap.to(box, { x: 100 });
// ❌ 不推荐:每次都要查询 DOM
gsap.to(".box", { x: 100 });3. 合理使用 ease
// ✅ 推荐:简单的缓动函数
gsap.to(".box", {
x: 100,
ease: "power2.out" // 性能好
});
// ⚠️ 谨慎使用:复杂的自定义缓动
gsap.to(".box", {
x: 100,
ease: function(t) {
// 复杂的计算可能影响性能
return Math.sin(t * Math.PI);
}
});4. 避免频繁更新
// ❌ 不推荐:频繁更新
gsap.to(".box", {
x: 100,
onUpdate: function() {
// 频繁执行可能影响性能
console.log(this.progress());
}
});
// ✅ 推荐:节流更新
let lastUpdate = 0;
gsap.to(".box", {
x: 100,
onUpdate: function() {
const now = performance.now();
if (now - lastUpdate > 100) { // 每 100ms 更新一次
console.log(this.progress());
lastUpdate = now;
}
}
});🔧 性能测试
性能基准测试
function performanceTest(iterations = 100) {
const startTime = performance.now();
for (let i = 0; i < iterations; i++) {
gsap.to(".test-box", {
x: Math.random() * 100,
duration: 0.1
});
}
const endTime = performance.now();
const duration = endTime - startTime;
const avgTime = duration / iterations;
console.log(`总耗时: ${duration}ms`);
console.log(`平均耗时: ${avgTime}ms`);
console.log(`理论 FPS: ${1000 / avgTime}`);
}📝 性能检查清单
开发时检查
- 使用 transform 和 opacity
- 避免动画 width、height、left、top
- 使用 Timeline 管理多个动画
- 使用 stagger 批量动画
- 合理使用 will-change
- 及时清理 ScrollTrigger
- 窗口大小改变时刷新 ScrollTrigger
生产环境检查
- 移除 markers
- 移除 console.log
- 优化动画数量
- 测试不同设备性能
- 监控实际 FPS