transform和opacity动画更流畅,因其由合成器线程处理,不触发重排重绘,仅合成;其他属性如width、left等需主线程计算样式与布局,易掉帧。

为什么 transform 和 opacity 动画更流畅
浏览器对 transform(如 translate、scale、rotate)和 opacity 的动画能直接交由合成器线程(Compositor Thread)处理,不触发重排(reflow)和重绘(repaint),只走“合成”阶段。其他属性(比如 width、height、left、top、background-color)会强制主线程计算样式和布局,容易掉帧。
- 用
transform: translateX(100px)替代left: 100px - 用
opacity: 0.5实现淡入淡出,别用visibility或display切换 - 避免在动画中读写
offsetWidth、getBoundingClientRect()等触发同步布局的 JS 操作
如何启用硬件加速又不滥用 will-change
will-change 会提前告诉浏览器“这个元素接下来要变”,促使它提前创建独立图层。但滥用会导致内存占用飙升、图层过多反而拖慢合成性能。
- 只对真正需要动画的元素设
will-change: transform或will-change: opacity - 动画开始前设置,结束后用 JS 清除(例如:动画
onfinish事件里设回will-change: auto) - 慎用
will-change: scroll-position或will-change: contents,它们开销极大 - Chrome DevTools 的 “Layers” 面板可查看图层数量,超过 20–30 层需警惕
用 @keyframes 写动画时的关键避坑点
CSS 动画本身轻量,但写法不当会隐式触发昂贵操作。重点不是“有没有动画”,而是“动的是什么”和“怎么动”。
- 避免在
@keyframes中混用transform和top/left—— 浏览器可能降级到软件渲染 - 减少关键帧数量:3 帧(
0%, 50%, 100%)比 10 帧更易保持 60fps - 用
ease-out或cubic-bezier(0.25, 0.46, 0.45, 0.94)替代ease-in-out,后者中间段速度变化太急,GPU 更难平滑插值 - 不要给
body或大容器加动画,优先作用于position: absolute或position: fixed的小元素
@keyframes slideIn {
0% {
transform: translateX(-100%);
opacity: 0;
}
100% {
transform: translateX(0);
opacity: 1;
}
}
.element {
animation: slideIn 0.3s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
/* 不要加 transition 或 animation-delay 过多层 */
}
动画卡顿时先查什么
别一上来就改代码。先确认是不是渲染瓶颈本身,而不是 CSS 写错了。
来自Adobe官方的Flash动画优化指南教程,包括以下的内容: • 如何节省内存 • 如何最大程度减小 CPU 使用量 • 如何提高 ActionScript 3.0 性能 • 加快呈现速度 • 优化网络交互 • 使用音频和视频 • 优化 SQL 数据库性能 • 基准测试和部署应用程序 …&hel
立即学习“前端免费学习笔记(深入)”;
- 打开 Chrome DevTools → “Performance” 标签 → 录制动画过程 → 查看“FPS”柱状图是否频繁跌破 45;点击低帧率区间,看 “Main” 轨道是否有长任务,“Rendering” 轨道是否密集出现 “Layout” 或 “Paint”
- 在 “Rendering” 设置中勾选 “FPS Meter” 和 “Layer Borders”,观察是否有意外的绿色图层(说明被提升为合成层)或大量重叠图层
- 用
chrome://flags/#rendering-frame-rate临时锁定 30fps,反向验证是否真为 GPU 负载问题 - 移动端务必测试真实设备——模拟器的 GPU 表现和真机差距极大
CSS 动画的性能分水岭不在“会不会写”,而在“动哪个属性”和“动多少东西”。很多卡顿其实源于一个 box-shadow 在滚动中反复重绘,或一个 filter: blur(2px) 把整块区域拖进软件渲染——这些细节比动画时长或缓动函数重要得多。







