如何实现鼠标悬停时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
相关产品推荐
相关产品推荐

