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

如何实现鼠标悬停时Translate动画速度减半且避免跳变?

解决苹果官网轮播悬停减速无跳变的问题

直接修改animation-duration会导致动画重置——浏览器会重新计算动画进度,让元素跳回起始位置,这就是你遇到鼠标移出时跳变的原因。要实现无缝减速/恢复,需要结合CSS变量和JavaScript跟踪动画进度,确保状态衔接。

实现步骤

1. HTML结构

先构建循环轮播的基础结构,复制一份内容实现无限滚动:

<div class="carousel">
  <div class="carousel-inner">
    <div class="carousel-item">服务1</div>
    <div class="carousel-item">服务2</div>
    <div class="carousel-item">服务3</div>
    <div class="carousel-item">服务4</div>
    <!-- 复制内容实现循环 -->
    <div class="carousel-item">服务1</div>
    <div class="carousel-item">服务2</div>
    <div class="carousel-item">服务3</div>
    <div class="carousel-item">服务4</div>
  </div>
</div>

2. CSS基础样式

用CSS变量控制动画时长,关键帧设置移动到一半宽度(因为复制了内容)实现循环:

.carousel {
  overflow: hidden;
  width: 100%;
}

.carousel-inner {
  display: flex;
  gap: 1.5rem;
  padding: 1rem 0;
  --duration: 5s;
  animation: scroll var(--duration) linear infinite;
}

.carousel-item {
  flex-shrink: 0;
  width: 200px;
  height: 120px;
  background: #f0f0f0;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 8px;
}

@keyframes scroll {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(-50%); /* 移动一半宽度,配合复制的内容实现循环 */
  }
}

3. JavaScript进度跟踪

通过JS监听动画状态,计算当前进度,在悬停/移出时调整动画时长和延迟,实现无缝衔接:

const carousel = document.querySelector('.carousel');
const carouselInner = carousel.querySelector('.carousel-inner');

let baseDuration = 5; // 初始时长(秒)
let currentDuration = baseDuration;
let startTime;
let elapsedTime = 0;

// 记录动画开始时间
carouselInner.addEventListener('animationstart', () => {
  startTime = performance.now();
});

// 动画循环时重置计时
carouselInner.addEventListener('animationiteration', () => {
  startTime = performance.now();
  elapsedTime = 0;
});

// 鼠标悬停:减速到原速度一半
carousel.addEventListener('mouseenter', () => {
  if (!startTime) return;
  
  elapsedTime = performance.now() - startTime;
  const progress = elapsedTime / (currentDuration * 1000);
  currentDuration = 10; // 减速后的时长
  
  // 计算剩余动画时间,设置负延迟让动画无缝继续
  const remainingTime = (1 - progress) * currentDuration;
  carouselInner.style.animationDuration = `${currentDuration}s`;
  carouselInner.style.animationDelay = `-${remainingTime}s`;
});

// 鼠标移出:恢复原速度
carousel.addEventListener('mouseleave', () => {
  if (!startTime) return;
  
  elapsedTime = performance.now() - startTime;
  const progress = elapsedTime / (currentDuration * 1000);
  currentDuration = baseDuration;
  
  const remainingTime = (1 - progress) * currentDuration;
  carouselInner.style.animationDuration = `${currentDuration}s`;
  carouselInner.style.animationDelay = `-${remainingTime}s`;
});

原理说明

  • 复制轮播内容并移动一半宽度,实现无限循环的视觉效果。
  • 通过performance.now()精准计算动画已执行的时长和进度。
  • 设置负的animation-delay,让新时长的动画从当前进度继续播放,避免跳变。

内容的提问来源于stack exchange,提问作者Robith Nuriel Haq

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 09:35:56