为什么我的动画元素在 Layers 面板里没单独成层?
我在做 CSS 动画优化,听说把元素提升到合成层能提升性能,但用 Chrome DevTools 的 Layers 面板看,加了 will-change: transform 的元素居然没单独成层,这是为啥?
我试过加 transform: translateZ(0) 也不行,代码很简单:
const box = document.querySelector('.box');
box.style.willChange = 'transform';
box.style.transition = 'transform 0.3s';
box.addEventListener('mouseenter', () => {
box.style.transform = 'scale(1.1)';
});
明明有 transform 变化,为什么 DevTools 里还是只有一个主 layer?
一是 will-change 设置的时机太晚了。 你在 JS 里等用户 mouseenter 的时候才设置 will-change,但浏览器这时候已经开始做动画了,根本来不及帮你创建合成层。will-change 得在动画开始前就声明,浏览器才有时间提前优化。
二是 Layers 面板需要你主动刷新。 你在控制台修改完样式后,Layers 面板不会自动更新,得点一下面板左上角的 "重新录制" 按钮或者刷新页面。
解决办法很简单:把 will-change 写到 CSS 里,别在 JS 里动态加。
这样写,浏览器在页面加载时就知道这个元素要动画,会提前创建合成层。
另外提醒一下,will-change 别滥用,一个页面里用多了反而会影响性能。一般对于那些确实需要频繁动画的元素(比如滚动列表里的项目)才需要加。
你可以试试看,这样设置后再打开 Layers 面板,应该就能看到单独的层了。
浏览器在解析到 will-change 时需要"提前准备"合成层,但你是在 JS 里动态设置的,这时候动画可能已经开始了,浏览器根本没来得及处理。
两种解决思路:
第一种,把 will-change 写进 CSS 里,提前让浏览器知道:
第二种,如果你必须动态设置,那就在动画开始前提前设,给浏览器留点准备时间:
另外提醒一下,看 Layers 面板的时候要在动画进行中的时候看,静态页面默认只会显示主层。动画跑起来之后刷新一下 Layers 面板就能看到了。
还有个土办法比 will-change 稳:直接上 translateZ(0) 或者 translate3d(0,0,0),这货基本能保证强制创建合成层: