动画 width/height 我跑了三年,今天 Chrome 终于让我放心了——值不变就上 Compositor,不用再担心主线程卡了
有一类动画我跑了三年,一直不太敢放手用——就是 width 和 height 的动画。不是因为做不出来,是因为浏览器每次都要把这类动画丢到主线程里跑,一跑起来整个页面都跟着卡。
Chrome 144 把这件事优化了,而且改法特别有意思:如果你动画里 width/height 的值从头到尾根本没变过,浏览器现在会跳过 Layout 阶段,直接把动画丢给 Compositor 处理。
这个变化解决了一个持续很久的认知矛盾。
以前教科书会告诉你「width/height 动画是性能杀手,能不用就不用」,理由是这些属性会触发布局,布局必须在主线程做,所以动画也会被拽到主线程。这个逻辑本身没问题,但它有个隐藏前提——我们默认 width/height 在动画过程中一定会变。
可实际上有大量场景,width/height 根本不变。
最典型的就是 View Transitions。切页面的时候,Chrome 会给旧页面和新页面的元素套上 ::view-transition-group(*) 这个伪元素,这些伪元素的 keyframe 里默认包含 width 和 height——但在实际过渡动画里,大多数元素的宽高根本不变。变的是 transform、opacity、color。按原来的逻辑,这些 View Transition 动画全都会被强制绑在主线程上,因为你写了 width/height,虽然值没动。
Chrome 144 的 Blink 引擎加了一个检测逻辑:在解析 keyframe 的时候,把所有 width/height 的值拿出来比一比。如果发现整条动画里宽高根本没变过,就跳过 Layout 阶段,动画可以直接跑在 Compositor 上。
之前光写 height: 100px 这行,Blink 就认定「有 width/height 属性参与」,直接拒绝 compositor。现在它会真正去检查值是否发生了变化。
这个变化影响最大的就是 View Transitions 动画。Bram.us 那边测试了 Chrome DevTools 的 trace,开启这个优化之后,View Transition 动画的 main thread 占用明显下降。页面切换动画终于可以放心用了,不用再担心「动画一跑,页面跟着抖」。
怎么用?
不用改代码。只要你的 Chrome 版本够新(144+),并且动画里 width/height 值真的没变化,浏览器自动就会走 compositor 路径。
想确认的话,打开 Chrome DevTools → Performance 面板,跑一次你的动画,看 Main Thread 火焰图里有没有 animation 相关的任务。如果优化生效了,animation 那条应该几乎是空的。
另外注意一点:目前 Chrome 对这个检测是严格相等判断,小数精度差异(比如 97.984px vs 97.9844px)会被当成不同值,导致优化失效。如果你的动画里用了百分比计算出的 height/width,浮动精度可能触发这个问题。这个 bug 已经有人在修了,可以蹲一下 crbug.com/399899726。
下一步
如果你现在在用 View Transitions API 做页面切换动画,升级 Chrome 到最新版就是最该做的事。动画还是那个动画,但性能已经不一样了。如果你是用纯 CSS 或 Web Animations API 做其他涉及 width/height 的动画,也值得跑一遍 DevTools trace 看看优化有没有生效。
很多性能问题不是代码写得不对,是浏览器还没来得及优化你写的那些代码。Chrome 144 补上了 width/height 动画这块短板。
评论区
登录后可评论。