应优先用 transform: translate() 而非 left/top 做平移动画,因后者触发重排、性能差且依赖定位上下文,而前者不触发重排、兼容性好、支持硬件加速。

用 transform: translate() 做平移动画,性能好、不触发重排,但直接改 left/top 会卡顿甚至失真——这是最该避开的坑。
为什么别用 left 和 top 做平移
改 left 或 top 会强制浏览器重新计算布局(reflow),尤其在动画循环中(比如 setInterval 每 16ms 更新一次),CPU 负担陡增,低端设备明显掉帧。更糟的是,如果父容器没设 position: relative,left 可能完全不生效;而 transform: translate() 不依赖定位上下文,只要元素存在就能动。
常见错误现象:box.style.left = '200px' 在部分安卓 WebView 里动画撕裂,或 Chrome DevTools 的“Rendering”面板里频繁标红“Layout”。
正确做法是统一走 transform:
立即学习“前端免费学习笔记(深入)”;
- 用
translateX()控制水平位移,正值向右,负值向左 - 用
translateY()控制垂直位移,正值向下,负值向上 - 想同时动两个方向?直接写
translate(100px, -50px),比分开调用更轻量
transition 和 @keyframes 怎么选
transition 适合「状态切换」:比如按钮点击后图片滑到新位置,再点一下滑回去。它依赖属性变化(如 class 切换或 JS 改 style),不能循环、也不能定义中间停顿点。
@keyframes 适合「路径可控」:比如 logo 从左到右再弹回,或沿折线移动。它由浏览器原生驱动,requestAnimationFrame 级精度,且可设 animation-iteration-count: infinite 循环。
关键差异:
-
transition必须配一个触发动作(如 hover、JS 改style.transform),否则不动 -
@keyframes一旦加到元素上就自动播,想暂停得用animation-play-state: paused -
transition的缓动函数(ease-in-out)作用于整个位移过程;@keyframes可在每个关键帧单独设animation-timing-function
JavaScript 动态控制 translate 的三个雷区
用 JS 改 style.transform 最灵活,但也最容易写出低效代码。以下三点必须检查:
- 别在循环里反复读取
offsetLeft或getBoundingClientRect()—— 这会强制同步布局计算,直接拖慢动画。应缓存起始值,用变量累加位移量 - 别拼字符串设
transform,比如el.style.transform = 'translateX(' + x + 'px)';优先用模板字面量或cssText批量更新 - 移动端要注意
transform的硬件加速开关:加will-change: transform或translateZ(0)可促发 GPU 渲染,但滥用会导致内存占用飙升,只在真正需要时加
一个安全示例:
let x = 0;
const box = document.querySelector('.box');
function animate() {
x += 2;
box.style.transform = `translateX(${x}px)`;
if (x < 400) requestAnimationFrame(animate);
}
animate();
Canvas 里平移图片和 DOM 平移的本质区别
Canvas 的 drawImage(img, x, y) 是「重绘」:每一帧都要清空画布、重新绘制图片。DOM 的 translate 是「图层合成」:浏览器把元素当成独立纹理,只挪位置不重绘内容。所以 Canvas 更适合做粒子、轨迹、逐帧变形等复杂效果;DOM 平移更适合 UI 元素的进出、切换、拖拽。
容易被忽略的一点:Canvas 中图片加载完成前就调用 drawImage,会静默失败(无报错),必须等 img.onload 触发后再启动动画循环。
如果你只是让一张 banner 图片左右滑动,用 CSS @keyframes 就够了;如果要响应鼠标拖拽并实时吸附边界,JS + transform 是唯一靠谱路径;只有当位移逻辑涉及物理模拟(比如抛物线、碰撞反弹)时,才值得切到 Canvas。



















