动画卡顿主因是帧率跌破20fps,根源在于不当读写布局属性、未隔离元素及未正确启用合成层。

动画里频繁重绘不是“卡一点”,而是帧率掉到 20fps 以下的明确信号——问题不在 JS 写得慢,而在你改了不该改的属性、读了不该读的值、没把元素真正“隔离”出来。
为什么 animation 帧率掉得快,getBoundingClientRect() 是头号嫌疑
在 requestAnimationFrame 回调里调用 getBoundingClientRect()、offsetTop 或 getComputedStyle(),等于命令浏览器立刻 flush 渲染队列、同步重排。每帧一次,就是每秒 60 次强制 layout —— GPU 合成层再快也扛不住。
- 所有读布局的操作必须集中放在一帧开头,且只读一次;写样式(如
element.style.transform)必须全放在结尾 - 若需基于位置做逻辑判断(比如碰撞检测),用上一帧缓存的坐标,而不是当场读
- 避免在动画循环中调用
scrollTop、clientWidth等任意以offset/client/scroll开头的属性
transform 和 opacity 不是“能用就行”,合并与提升才是关键
只写 transform: translateX(10px) 不够,它仍可能被父容器约束、参与行高计算、拖累兄弟节点重绘。真正零阻塞需要两步:合并变换 + 图层提升。
- 把多个
transform操作合并为单条声明,例如用transform: translate(10px, 5px) scale(1.2) rotate(5deg),而非分多次设translateX和rotate - 移动端优先加
transform: translateZ(0)触发图层提升;Safari 对will-change: transform支持弱,且易误触发内存泄漏 - 多个相邻动效元素,包裹进同一个
<div>并只对该容器加提升,别给每个图标/文字单独加translateZ(0) - 提升后元素行为类似
position: absolute,若布局错位,检查是否依赖了原本文档流中的 baseline 或行高
哪些 CSS 属性改了就必然重排,动画里必须绕开
直接改 left、top、width、height、margin、padding,等于每帧都要求浏览器重新计算整个布局树。这不是“建议不用”,而是“用了就掉帧”。
立即学习“前端免费学习笔记(深入)”;
- 替代方案只有两个:用
transform控制位移/缩放/旋转,用opacity控制显隐/透明度 -
display: none或visibility: hidden切换会触发布局变化,不能用于逐帧控制 - 慎用
filter(如blur()、drop-shadow()):虽不重排,但会触发全量重绘,GPU 负担高,低端设备易掉帧 - 避免对
display: inline元素直接加transform,baseline 计算不稳定,可能意外触发重绘
真正难的不是知道该用 transform,而是确认它确实走的是合成层——打开 Chrome DevTools 的 Layers 面板,看到动画元素独立成层,且没有“Paint”字样高频闪烁,才算落地。否则,写了也是白写。



















