浏览器对transform和opacity的过渡能走gpu合成层,其他属性基本都得走cpu重排或重绘;混入left等非合成属性会导致整条过渡降级掉帧;正确做法是仅声明transform和opacity,避免all和父级压制,确保真gpu加速。

transition写在非合成属性上必然卡顿
浏览器对transform和opacity的过渡能走GPU合成层,其他属性基本都得走CPU重排或重绘。只要transition里混进一个left、width、background-color或box-shadow,整条过渡就降级——不是部分卡,是全部掉帧。
常见错误写法:transition: left 0.3s, background-color 0.3s; → 即使只动left,background-color也会拖垮整条链
- 正确做法:只声明
transform和opacity,例如transition: transform 0.2s, opacity 0.2s; - 绝对不要用
transition: all 0.3s——它等于把所有属性都扔进过渡队列,某次意外改了margin就静默卡顿 - 动画开始前确保元素有初始
transform值,比如transform: translateX(0),否则首次触发会跳变
父容器正在悄悄破坏GPU加速
即使你写了transform: translateX(10px),动画仍卡?大概率是父级容器在“拖后腿”。overflow: hidden、filter: blur(1px)、backdrop-filter、mask这些属性会让子元素无法独立成层,被迫回退到CPU渲染。
验证方式:Chrome DevTools → Rendering → 勾选“Layer borders”,绿色边框才表示真提层;没绿框,就说明被父级压制了
- 临时解法:给动画元素加
transform: translate3d(0, 0, 0)或backface-visibility: hidden强制升层(IE11下后者更稳) - 慎用
will-change: transform:它在iOS Safari旧版无效,在Android 4.4可能闪烁,不如直接上translate3d - 别全局写
* { will-change: transform; }——一屏20个列表项,低端机容易OOM卡死
滚动中读写样式引发layout thrashing
滚动监听里最隐蔽的卡顿源:在scroll事件里一边写style.transform,一边立刻读getBoundingClientRect()或offsetTop。这会让浏览器每帧都强制同步计算布局,尤其在iOS Safari 9–10和Android 4.4 WebView里首帧就掉。
- 必须把读操作包进
requestAnimationFrame,并确保“先批量写,下一帧再读” - 避免在
scroll中动态加class后又马上改style.transform——过渡链断裂,退化为跳变 - DevTools → Rendering → 勾选“Layout Shift Regions”,看是否有意外的layout波动区域
移动端touch延迟让动画根本没启动
iOS Safari和部分安卓WebView在touchstart后默认等300ms判定是否双击缩放,这期间主线程被阻塞,transition根本没真正开始。
- 加
touch-action: manipulation到目标元素,可禁用双击缩放检测 - 监听
touchstart时立刻设el.style.willChange = 'transform',但记得在transitionend后清掉;iOS对≤16ms动画可能不触发该事件,需加setTimeout兜底 - 滚动驱动视差动画时,别用
background-position——旧Android不硬件加速,改用transform: translateX()模拟
真实卡顿往往不出现在transition声明本身,而藏在父容器、滚动逻辑或touch交互链里。哪怕写了transform,只要其中一环触发重排或被父级压制,整段动画就退回CPU。验证图层是否真绿,比调duration数字重要得多。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











