用 transform 做动画真的能提升性能吗?为什么我的页面还是卡?

长孙秀英 阅读 68

我听说用 transform 做动画不会触发重排,应该更流畅,但我在做一个滑动菜单时还是明显卡顿,是不是哪里写错了?

我试过只用 transform: translateX 来移动元素,也加了 will-change: transform,但低端机上滑动还是掉帧。下面是我的简化代码:

const menu = document.querySelector('.menu');
let x = 0;
document.addEventListener('mousemove', (e) => {
  x = e.clientX - 100;
  menu.style.transform = <code>translateX(${x}px)</code>;
});

难道光用 transform 不够?还需要配合其他优化手段吗?

我来解答 赞 16 收藏
二维码
手机扫码查看
2 条解答
Good“令敏
用 transform 做动画确实可以提升性能,因为它通常只会触发重绘而不会触发重排。但是,你的页面卡顿可能不仅仅是这个原因。首先,mousemove 事件在某些设备上会非常频繁地触发,尤其是在低端机上,这会导致大量的计算和样式更新。

常见的解决方案是使用 requestAnimationFrame 来限制动画的更新频率,确保它与显示器的刷新率同步。你可以试试下面这种方式来优化你的代码:

const menu = document.querySelector('.menu');
let x = 0;
let lastKnownScrollPosition = 0;
let ticking = false;

function doSomething(scrollPos) {
x = scrollPos - 100;
menu.style.transform = translateX(${x}px);
}

document.addEventListener('mousemove', function(e) {
lastKnownScrollPosition = e.clientX;

if (!ticking) {
window.requestAnimationFrame(function() {
doSomething(lastKnownScrollPosition);
ticking = false;
});

ticking = true;
}
});


这样,无论 mousemove 事件触发多少次,动画更新都会被限制在每帧一次。另外,确保你的 .menu 元素没有复杂的样式,特别是避免使用容易导致重绘的属性,比如 background-image 或 box-shadow。这些优化结合起来应该能改善你在低端机上的性能问题。
点赞
2026-03-23 14:09
端木毓珂
问题在于 mousemove触发频率太高,每帧都直接操作 DOM 样式,再好的属性也扛不住。

省事的话,用 requestAnimationFrame 包装一下,让浏览器自己优化更新时机:

const menu = document.querySelector('.menu');
let x = 0;
let targetX = 0;

document.addEventListener('mousemove', (e) => {
targetX = e.clientX - 100;
});

function animate() {
// 简单的缓动效果
x += (targetX - x) * 0.1;
menu.style.transform = translateX(${x}px);
requestAnimationFrame(animate);
}

animate();


或者更懒——直接用 CSS transition,鼠标移入移出时自动平滑:

.menu {
transition: transform 0.3s ease-out;
/* 别忘了这个 */
will-change: transform;
}


document.addEventListener('mousemove', (e) => {
menu.style.transform = translateX(${e.clientX - 100}px);
});


第二种写法代码少一半,性能反而更好,因为 CSS 动画跑在合成线程上,不受 JS 主线程阻塞影响。
点赞 1
2026-03-14 03:03