如何实现CSS动画平缓停止?含圆周运动圆圈交互需求
实现圆周运动圆圈的平缓停止效果
原生JS方案(精准控制)
这个方案能让圆圈精准停在鼠标hover瞬间的位置,同时实现平滑过渡,适合需要精确控制的场景:
1. HTML结构
<div class="circle-container"> <div class="circle circle-1"></div> <div class="circle circle-2"></div> <div class="circle circle-3"></div> <div class="circle circle-4"></div> </div>
2. CSS基础样式
.circle-container { position: relative; width: 300px; height: 300px; margin: 50px auto; } .circle { position: absolute; width: 50px; height: 50px; border-radius: 50%; background: #3498db; /* 圆周循环动画 */ animation: orbit 4s linear infinite; /* 给transform添加过渡,用于平滑停止和中心移动 */ transition: transform 0.5s ease; } /* 四个圆圈的初始圆周位置 */ .circle-1 { left: calc(50% - 25px); top: -25px; } .circle-2 { right: -25px; top: calc(50% - 25px); } .circle-3 { left: calc(50% - 25px); bottom: -25px; } .circle-4 { left: -25px; top: calc(50% - 25px); } /* 圆周运动关键帧:旋转+平移实现绕中心转圈 */ @keyframes orbit { to { transform: rotate(360deg) translate(150px) rotate(-360deg); } } /* hover时被选中圆圈的中心放大状态 */ .circle.center { transform: translate(calc(50% - 25px), calc(50% - 25px)) scale(1.5); }
3. JS控制逻辑
const circles = document.querySelectorAll('.circle'); const container = document.querySelector('.circle-container'); // 存储每个圆圈的动画实例和状态 const circleAnimationData = []; // 初始化:记录每个圆圈的动画信息 circles.forEach(circle => { const anim = circle.getAnimations()[0]; circleAnimationData.push({ element: circle, animation: anim, totalDuration: anim.effect.getTiming().duration }); }); // 鼠标进入容器(hover圆圈时触发) container.addEventListener('mouseenter', (e) => { if (!e.target.classList.contains('circle')) return; // 处理所有圆圈的平缓停止 circleAnimationData.forEach(({ element, animation }) => { // 暂停当前动画 animation.pause(); // 获取圆圈当前的transform状态(动画运行到的位置) const currentTransform = getComputedStyle(element).transform; // 移除循环动画,把transform固定在当前位置(transition会让这个变化平滑) element.style.animation = 'none'; element.style.transform = currentTransform; }); // 让被hover的圆圈移到中心并放大 e.target.classList.add('center'); }); // 鼠标离开容器时恢复动画 container.addEventListener('mouseleave', () => { circles.forEach(circle => { circle.classList.remove('center'); // 恢复循环动画 circle.style.animation = ''; // 找到对应的动画实例,设置回之前的进度,让动画从暂停位置继续 const data = circleAnimationData.find(item => item.element === circle); if (data) { const progress = data.animation.currentTime / data.totalDuration; data.animation.cancel(); data.animation.play(); data.animation.currentTime = progress * data.totalDuration; } }); });
方案说明
- 核心是利用
transition作用于transform属性,当hover时把动态动画替换成固定的transform值,实现平滑停止。 - 通过JS记录动画进度,鼠标离开时能让动画从暂停位置继续播放,不会跳帧。
纯CSS折中方案(简单但不精准)
如果不想用JS,可以用这个方案,视觉上能实现平缓停止,但圆圈会继续运动到圆周终点再停下:
修改后的CSS
.circle { animation: orbit 4s linear infinite; transition: transform 0.5s ease; } /* hover时,给非中心圆圈切换成减速停止的动画 */ .circle-container:hover .circle:not(.center) { animation: orbit-stop 0.5s ease-out forwards; } /* 被hover的圆圈取消动画,用过渡实现中心移动 */ .circle-container:hover .circle.center { animation: none; } /* 减速停止的关键帧,用ease-out实现减速效果 */ @keyframes orbit-stop { to { transform: rotate(360deg) translate(150px) rotate(-360deg); } }
方案说明
- 利用
ease-out的动画曲线让圆圈减速到停止,不需要JS,但停止位置是圆周的终点,不是hover瞬间的位置。 - 实现简单,适合对停止位置没有严格要求的场景。
内容的提问来源于stack exchange,提问作者anonymous017
相关产品推荐
相关产品推荐

