如何在Javascript中使用@keyframes实现CSS动画中途JS接管效果
CSS @keyframes 动画运行到90%时由JS接管的实现方案
核心实现思路
要保证动画全程连贯无卡顿,需满足两个要求:精准捕获90%进度的时间节点,接管时直接继承元素当前的实际动画状态,避免视觉跳变。
第一步:调整CSS配置
先补全@keyframes的完整动画路径,设置好动画总时长,添加forwards属性保证动画结束前保持当前状态:
@keyframes spin { 0% { transform: rotate(0deg); } 50% { transform: rotate(1080deg); } 100% { /* 先补全CSS端的终点状态,用于进度计算,实际到90%就会被JS接管 */ transform: rotate(2160deg); } } /* 动画绑定的元素示例 */ #spin-container { width: 100px; height: 100px; background: #2563eb; /* 动画配置:总时长10s、线性运动、保持最后一帧状态,可根据需求调整 */ animation: spin 10s linear forwards; }
第二步:JS逻辑实现
通过animationstart事件获取动画准确启动时间,用requestAnimationFrame轮询进度,到90%时接管动画:
const container = document.getElementById('spin-container'); // 和CSS配置保持一致的总动画时长,单位毫秒 const TOTAL_DURATION = 10 * 1000; // 90%进度对应的接管时间点 const HANDOVER_POINT = TOTAL_DURATION * 0.9; let animationStartTime = null; let isJsControl = false; // 监听动画启动事件,获取精准启动时间 container.addEventListener('animationstart', (e) => { if (e.animationName === 'spin') { animationStartTime = performance.now(); requestAnimationFrame(checkProgress); } }); function checkProgress() { if (isJsControl) return; const runTime = performance.now() - animationStartTime; // 到达接管时间点 if (runTime >= HANDOVER_POINT) { // 取消CSS动画,避免和JS控制冲突 container.style.animation = 'none'; // 读取元素当前实际的旋转角度,保证衔接无跳变 const matrix = new DOMMatrix(getComputedStyle(container).transform); let currentDeg = Math.atan2(matrix.b, matrix.a) * 180 / Math.PI; // 处理角度为负值的情况 currentDeg = currentDeg < 0 ? currentDeg + 360 : currentDeg; // 补全多圈旋转的总角度,避免只取到0-360区间的数值 const expectedDeg = 2160 * 0.9; currentDeg += Math.floor(expectedDeg / 360) * 360; isJsControl = true; // 后续JS自定义动画逻辑,可替换为你的业务逻辑 function runJsAnimation() { currentDeg += 1.5; // 自定义旋转速度 container.style.transform = `rotate(${currentDeg}deg)`; requestAnimationFrame(runJsAnimation); } runJsAnimation(); return; } requestAnimationFrame(checkProgress); }
注意事项
- 如果动画使用非匀速的缓动函数,不要依赖预计算的角度值,直接以getComputedStyle读取到的实际变换矩阵计算的角度为准,避免进度计算偏差
- 不要用setTimeout做进度监听,主线程阻塞会导致时间偏差,requestAnimationFrame和动画刷新频率同步,进度判断更准确
- 接管时必须先取消CSS动画,否则CSS的动画规则会和JS设置的transform属性冲突,出现元素抖动的情况
内容的提问来源于stack exchange,提问作者DavidJambonski
相关产品推荐
相关产品推荐

