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

如何实现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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 07:30:39