缓动函数怎么让动画更自然?

令狐春红 阅读 14

我用JS写了个简单的元素移动动画,但感觉生硬卡顿,不像CSS transition那样顺滑。是不是缓动函数没选对?

试过直接改 time / duration 的比例,但效果还是线性的。网上说要用 easeInOut 之类的,但不知道怎么集成进我的代码里。

function animate(el, duration) {
  const start = Date.now();
  const startX = 0;
  const endX = 300;

  function step() {
    const elapsed = Date.now() - start;
    const progress = Math.min(elapsed / duration, 1);
    // 这里直接用了线性插值,是不是问题出在这?
    el.style.transform = <code>translateX(${startX + (endX - startX) * progress}px)</code>;
    
    if (progress < 1) requestAnimationFrame(step);
  }
  requestAnimationFrame(step);
}
我来解答 赞 4 收藏
二维码
手机扫码查看
1 条解答
闲人玉飞
对,你猜对了,问题就出在 linear 插值上。线性动画就是从头到尾一个速度,肯定生硬。

核心思路很简单:progress 传入缓动函数,算出一个"调整后的 progress",再用这个值做插值。缓动函数把线性时间映射成曲线,这样开始慢、中间快、结束慢,视觉上就顺滑了。

常见的缓动函数:

// 二次缓动,比较常用
function easeInOutQuad(t) {
return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t;
}

// 更柔和的版本
function easeInOutSine(t) {
return -(Math.cos(Math.PI * t) - 1) / 2;
}


然后改一下你的 step 函数,就加一行:

function animate(el, duration) {
const start = Date.now();
const startX = 0;
const endX = 300;

function step() {
const elapsed = Date.now() - start;
const progress = Math.min(elapsed / duration, 1);
const eased = easeInOutQuad(progress); // 加上这行
el.style.transform = translateX(${startX + (endX - startX) * eased}px);

if (progress < 1) requestAnimationFrame(step);
}
requestAnimationFrame(step);
}


就酱。easeInOutQuad 足够应付大多数场景,如果想要更夸张的缓动效果可以试试 cubic 版本的,或者直接搜「JS easing functions」找现成的。
点赞 2
2026-03-11 18:03