使用 will-change 提升动画性能,为什么反而更卡了?
我在做一个移动端的下拉刷新动画,听说加 will-change: transform 能提升性能,就给元素加上了。但实际测试发现,动画反而变得更卡顿了,这是为啥?
我是在 touchmove 时动态设置 will-change 的,代码大概是这样:
element.addEventListener('touchstart', () => {
element.style.willChange = 'transform';
});
element.addEventListener('touchend', () => {
element.style.willChange = 'auto';
});
是不是用法有问题?还是说在某些机型上适得其反?
will-change本身不是魔法,它是有成本的。你现在的写法最大的问题在于触发的时机。当你在
touchstart事件里动态设置will-change时,浏览器需要在用户手指按下的那一瞬间,立刻为这个元素建立一个新的合成层,并分配 GPU 资源。这个建立过程本身就是耗时的,正好卡在了动画开始的第一帧,所以你会感觉到明显的掉帧。这就好比我们后端处理高并发请求,不能等请求进来了才去建立数据库连接池,那样肯定超时。正确的做法是提前预热。
另外,频繁地开启和关闭
will-change(你在touchstart开,touchend关),会导致浏览器频繁地创建和销毁图层,增加了垃圾回收(GC)的压力,这在低端机上更明显。针对下拉刷新这种场景,我有两个建议:
第一,如果这个元素确定要频繁动画,直接在 CSS 里静态写死
will-change: transform,或者用老派的transform: translateZ(0)强制开启硬件加速,别用 JS 动态去切。第二,如果非要用 JS 动态控制,一定要在动画开始之前就把
will-change加上,给浏览器一点喘息和准备的时间,别卡在touchstart这种高频事件里。给你改个写法参考一下,直接在 CSS 里搞定最省事:
这样浏览器在页面加载渲染的时候就会把层建好,
touchmove的时候直接用 GPU 跑,丝般顺滑。别为了省那点显存而在 JS 里折腾,得不偿失。