You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

更新CSS动画参数时实现平滑过渡的方法

问题描述

现有一个id为box的HTML元素:

<div id="box"></div>

初始设置该盒子4秒内向右移动200像素,CSS代码如下:

.anim {
    animation-name: anim;
    animation-duration: 4s; 
    animation-timing-function: linear; /* cubic-bezier(0.1, -0.6, 0.2, 0); */
}

@keyframes anim {
    0% { left: var(--xs); }
    100% { left: var(--xe); }
}

启动动画的JavaScript代码:

var box = document.getElementById('box');

box.style.setProperty('--xs', '0px');
box.style.setProperty('--xe', '200px');
box.classList.add('anim');

1秒后尝试将最终位置更新为400像素:

setTimeout(() => {
    box.style.setProperty('--xe', '400px');
},1000)

此时盒子会出现位置跳变,需实现平滑过渡避免“瞬移”效果。

解决方案

问题根源在于CSS动画启动后,关键帧参数的更新会直接基于新值重新计算整个动画进度,导致位置跳变。以下两种方式可实现平滑衔接:

方法一:基于现有动画状态重置动画

通过获取当前动画的实时进度,重新计算起始位置、剩余时长,再重启动画:

var box = document.getElementById('box');

// 初始化动画
box.style.setProperty('--xs', '0px');
box.style.setProperty('--xe', '200px');
box.classList.add('anim');

setTimeout(() => {
    // 获取当前动画实例与状态
    const anim = box.getAnimations()[0];
    const elapsedTime = anim.currentTime;
    const totalDuration = anim.effect.getTiming().duration;
    const remainingTime = totalDuration - elapsedTime;
    
    // 获取盒子当前的实时位置
    const currentLeft = parseFloat(getComputedStyle(box).left);
    
    // 清除当前动画
    anim.cancel();
    box.classList.remove('anim');
    
    // 设置新的动画参数
    box.style.setProperty('--xs', `${currentLeft}px`);
    box.style.setProperty('--xe', '400px');
    box.style.animationDuration = `${remainingTime}s`;
    
    // 重启动画
    box.classList.add('anim');
}, 1000);

对应的CSS需补充animation-fill-mode以保持结束状态:

.anim {
    animation-name: anim;
    animation-duration: 4s; 
    animation-timing-function: linear;
    animation-fill-mode: forwards;
}

@keyframes anim {
    0% { left: var(--xs); }
    100% { left: var(--xe); }
}

方法二:改用CSS过渡(transition)实现

过渡特性支持属性更新时自动平滑过渡,只需计算剩余过渡时长即可保持匀速:

#box {
    position: absolute;
    left: 0;
    transition: left linear;
}
var box = document.getElementById('box');

// 初始设置:4秒移动到200px
box.style.transitionDuration = '4s';
box.style.left = '200px';

setTimeout(() => {
    // 计算当前位置与剩余距离
    const currentLeft = parseFloat(getComputedStyle(box).left);
    const remainingDistance = 400 - currentLeft;
    // 原速度为50px/秒,计算剩余距离所需时长
    const remainingTime = (remainingDistance / 50) + 's';
    
    // 更新过渡参数
    box.style.transitionDuration = remainingTime;
    box.style.left = '400px';
}, 1000);

内容的提问来源于stack exchange,提问作者Fifi

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 17:17:28