
本文介绍如何通过纯 css 实现一个无缝、无闪烁的无限轮播效果,并在鼠标悬停左侧热区时动态提升滚动速度,避免因动画状态切换导致的视觉跳变或“双层幻影”现象。
本文介绍如何通过纯 css 实现一个无缝、无闪烁的无限轮播效果,并在鼠标悬停左侧热区时动态提升滚动速度,避免因动画状态切换导致的视觉跳变或“双层幻影”现象。
实现一个真正平滑的无限轮播(尤其是带悬停加速功能)的关键,在于避免直接修改 animation-duration —— 这会导致浏览器强制重置动画计时器,造成当前帧突变、位移错位,从而出现你观察到的“两行圆圈交替可见”的诡异行为:原动画未完成就被中断,新动画从头开始,而 DOM 中多个 .first-row 元素又各自独立运行动画,视觉上便产生重影与撕裂。
✅ 正确思路是:复用同一套动画逻辑,仅通过 animation-play-state 控制播放/暂停,并借助嵌套容器分离“基础滚动”与“加速滚动”通道,让加速态自然接管视觉呈现,而非覆盖或重置。
✅ 推荐结构:双层容器 + 悬停驱动播放态切换
我们采用三层 DOM 结构:
- 外层
.moving-circles:负责布局与悬停检测(利用:has()); - 中层
.rows-wrapp:承载加速动画(默认paused),悬停时running; - 内层
.rows:承载常速动画(默认running),悬停时paused。
这样,两个动画始终同步位移逻辑(同 keyframes、同方向),仅播放状态不同;悬停瞬间,常速层暂停,加速层启动——由于两者起始位置一致(CSS 动画初始态由 from 定义),视觉无缝接续,毫无跳变。
? 核心 CSS 技巧解析
@keyframes slide {
from { transform: translateX(0); }
to { transform: translateX(-33.333%); } /* 关键!只移动1/3宽度,适配3行循环 */
}
.moving-circles {
display: flex;
&:has(.left:hover) {
.rows-wrapp { animation-play-state: running; }
.rows { animation-play-state: paused; }
}
}
.rows-wrapp {
animation: 5s slide infinite linear paused; /* 加速态:5s 一圈 */
display: flex;
}
.rows {
animation: 10s slide infinite linear; /* 常速态:10s 一圈 */
display: flex;
}
⚠️ 注意
translateX(-33.333%)的设定:因.rows内含 3 个完全相同的.row(水平并排),总宽度为300%,要实现无缝循环,只需让动画位移-100%的 单行宽度 → 即-33.333%的 容器宽度。这是无限轮播不露破绽的核心数学依据。
? HTML 结构精简示意(含三行冗余数据)
<nav class="moving-circles"><div class="left"></div>
<div class="rows-wrapp">
<div class="rows">
<div class="row"><!-- 0-9 --></div>
<div class="row"><!-- 0-9 --></div>
<div class="row"><!-- 0-9 --></div>
</div>
</div>
</nav>
每 .row 包含完整数字序列(0–9),三行确保无论何时截断,视口内始终有足够内容填充——这是无限滚动的“缓冲带”设计。
? 样式增强建议
- 使用
border-radius: 50%替代大数值1000px,更语义化; - 为
添加display: grid; place-items: center,比flex更简洁居中; -
.left使用inset: 0 auto 0 -128px替代top/left/width/height,更健壮; - 移除冗余
white-space: nowrap(display: flex已隐含); - 背景色统一用
#fff或透明,避免遮挡。
✅ 最终效果验证要点
| 状态 | 行为 | 验证方式 |
|---|---|---|
| 默认 |
.rows 以 10s 匀速滚动,.rows-wrapp 暂停 |
观察滚动节奏是否稳定 |
悬停 .left
|
.rows 暂停,.rows-wrapp 以 5s 加速滚动 |
速度应瞬时提升,无卡顿、无重影 |
| 移出 | 自动切回常速,位置连续无跳帧 | 检查数字序列是否连贯(如 7→8→9→0 不中断) |
✅ 总结:不要改
duration,要控play-state;不要靠 JS 操控样式,要用:has()做声明式响应;不要两行“竞争”,要三层“协同”——这才是现代 CSS 无限轮播的优雅解法。










