javascript如何实现简单的动画效果?【教程】

用requestAnimationFrame替代setTimeout可实现平滑动画,因其由浏览器统一调度绘制时机;需在回调末尾递归调用自身,避免耗时操作,并可用performance.now()控制时间差。

requestAnimationFrame 替代 setTimeout 实现平滑动画

直接用 setTimeout 控制样式变化容易掉帧,尤其在页面负载高时。浏览器无法协调绘制时机,导致卡顿或跳变。r

equestAnimationFrame 会把动画逻辑交给浏览器统一调度,保证每帧在下一次重绘前执行,是 Web 动画的底层推荐方式。

  • 必须在回调函数末尾再次调用 requestAnimationFrame 才能持续执行
  • 不要在回调里做耗时操作(如 DOM 查询、大量计算),否则会挤占渲染时间
  • 可配合 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 更轻量、更稳定,且支持硬件加速。关键不是写动画本身,而是控制触发时机和过渡参数。

  • 必须提前在 CSS 中定义 transition,仅靠 JS 改变 style 不会生效
  • 避免同时过渡多个属性(如 left + top + opacity),优先用 transformopacity
  • 过渡时间单位用 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 更简洁,且自带播放控制能力(暂停、反向、时间偏移)。

  • 不兼容 IE,Safari 16.4+ 才支持 iterationStart 等高级参数
  • 动画结束后默认不保留最终状态,需显式设置 fill: 'forwards'
  • 传入的 keyframes 对象中,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 动画性能差?

修改 lefttop 会触发浏览器强制同步布局(layout),每次重排都要重新计算整个文档流,代价远高于只改 transform(只影响合成层)。

  • 即使元素已设 position: absoluteleft 变化仍会引发 layout
  • transform: translateX() 不影响文档流,且大多数情况下走 GPU 合成,帧率更稳
  • 检查工具:Chrome DevTools 的 Rendering 面板打开 “Paint flashing” 和 “FPS meter”,对比两种写法的闪烁区域和帧率波动

复杂动画真正难的不是“怎么动起来”,而是“怎么动得准、停得稳、不抢主线程”。比如缓动函数选错、未清理旧动画句柄、CSS 触发重排却不自知——这些细节比写第一行 requestAnimationFrame 更容易让效果失真。