用requestAnimationFrame替代setTimeout可实现平滑动画,因其由浏览器统一调度绘制时机;需在回调末尾递归调用自身,避免耗时操作,并可用performance.now()控制时间差。
requestAnimationFrame 替代 setTimeout 实现平滑动画直接用 setTimeout 控制样式变化容易掉帧,尤其在页面负载高时。浏览器无法协调绘制时机,导致卡顿或跳变。requestAnimationFrame 会把动画逻辑交给浏览器统一调度,保证每帧在下一次重绘前执行,是 Web 动画的底层推荐方式。
requestAnimationFrame 才能持续执行performance.now() 做时间差控制,实现精确的缓动逻辑let startTime = null;
function animate(timestamp) {
if (!startTime) startTime = timestamp;
const elapsed = timestamp - startTime;
const progress = Math.min(elapsed / 1000, 1); // 持续1秒
element.style.transform = `translateX(${progress * 200}px)`;
if (progress < 1) requestAnimationFrame(animate);
}
requestAnimationFrame(animate);transition CSS 属性做声明式位移动画对简单位移、缩放、透明度变化,纯 CSS 更轻量、更稳定,且支持硬件加速。关键不是写动画本身,而是控制触发时机和过渡参数。
transition,仅靠 JS 改变 style 不会生效left + top + opacity),优先用 transform 和 opacity
ms 更易控制,例如 transition: transform 300ms ease-out
/* CSS */
.box { transition: transform 250ms cubic-bezier(0.25, 0.46, 0.45, 0.94); }
.box.active { transform: translateX(100px); }
/ JS /
element.classList.add('active');
animate() API 实现可控的关键帧动画Element.animate() 是现代浏览器原生支持的 JavaScript 动画接口,比手动管理 requestAnimationFrame 更简洁,且自带播放控制能力(暂停、反向、时间偏移)。
iterationStart 等高级参数fill: 'forwards'
offset 值必须在 0–1 之间,且有序element.animate(
[
{ transform: 'scale(1)', opacity: 1 },
{ transform: 'scale(1.2)', opacity: 0.7 }
],
{
duration: 400,
fill: 'forwards',
easing: 'ease-in-out'
}
);left/top 动画性能差?修改 left 或 top 会触发浏览器强制同步布局(layout),每次重排都要重新计算整个文档流,代价远高于只改 transform(只影响合成层)。
position: absolute,left 变化仍会引发 layouttransform: translateX() 不影响文档流,且大多数情况下走 GPU 合成,帧率更稳复杂动画真正难的不是“怎么动起来”,而是“怎么动得准、停得稳、不抢主线程”。比如缓动函数选错、未清理旧动画句柄、CSS 触发重排却不自知——这些细节比写第一行 requestAnimationFrame 更容易让效果失真。