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

CSS keyframes实现滚动轮播 动画循环衔接存在延迟跳变问题

无缝自动轮播跳变问题修复

问题根源

你当前代码出现循环跳变有3个核心原因:

  • 动画类错误添加到了每个独立的图片容器上,多个元素各自执行位移动画,无法实现衔接
  • CSS伪元素选择器书写错误,.slider::after匹配不到对应元素,两侧渐变遮罩失效
  • 若使用CSS keyframes实现无限滚动,需要保证动画结束位置和起始位置的视觉状态完全一致,否则会出现瞬时跳回的断档感

方案一:修正后的纯CSS实现(无需JS)

这个方案不需要引入requestAnimationFrame,只要调整DOM结构和CSS规则即可实现无缝滚动:

  1. 新增统一的滚动轨道容器,把两份图片内容都放在轨道内,动画只添加到轨道元素上
  2. 动画位移距离设置为单份内容的总宽度,滚完100%时刚好第二份内容对齐初始位置,无视觉跳变
  3. 修正伪元素选择器错误

完整代码如下:

<div style="max-width: 800px;">
  <div class="carousel-wrapper">
    <div class="carousel-slider">
      <!-- 统一的滚动轨道 -->
      <div class="slides-track">
        <div class="image-container">
          <a href="#"><img src="https://picsum.photos/id/10/200/85" alt="image1"></a>
          <a href="#"><img src="https://picsum.photos/id/11/200/85" alt="image2"></a>
          <a href="#"><img src="https://picsum.photos/id/12/200/85" alt="image3"></a>
        </div>
        <div class="image-container">
          <a href="#"><img src="https://picsum.photos/id/10/200/85" alt="image1"></a>
          <a href="#"><img src="https://picsum.photos/id/11/200/85" alt="image2"></a>
          <a href="#"><img src="https://picsum.photos/id/12/200/85" alt="image3"></a>
        </div>
      </div>
    </div>
  </div>
</div>
.carousel-wrapper {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.carousel-slider {
  height: 100px;
  position: relative;
  overflow: hidden;
}

.slides-track {
  height: 100px;
  display: flex;
  align-items: center;
  /* 动画时长根据内容宽度调整,速度保持均匀 */
  animation: slideshow 5s linear infinite;
}

.image-container {
  display: flex;
  align-items: center;
}

.image-container img {
  height: 85px;
  padding: 0 8px;
}

@keyframes slideshow {
  0% {
    transform: translateX(0);
  }
  100% {
    /* 刚好位移一个图片容器的宽度,此时第二组图和初始位置重合 */
    transform: translateX(-50%);
  }
}

/* 修正伪元素选择器 */
.carousel-slider::before,
.carousel-slider::after {
  height: 100px;
  width: 50px;
  position: absolute;
  content: "";
  z-index: 2;
}

.carousel-slider::before {
  left: 0;
  top: 0;
  background: linear-gradient(to right, #fff 0%, rgba(255,255,255,0) 100%);
}

.carousel-slider::after {
  right: 0;
  top: 0;
  background: linear-gradient(to left, #fff 0%, rgba(255,255,255,0) 100%);
}
// 纯CSS方案不需要额外JS,移除原来给每个image-container加类的代码即可

方案二:基于requestAnimationFrame的JS实现

如果需要更灵活的滚动控制(比如鼠标悬停暂停、动态调整速度、增减内容),可以用requestAnimationFrame实现,逻辑如下:

  • 初始化时获取单份内容宽度、轨道元素,设置滚动速度
  • 每帧更新位移值,当位移超过单份内容宽度时直接重置为0,利用两份内容完全一致的特点实现无缝衔接
  • 监听页面可见性变化,页面切走时暂停动画减少性能消耗

完整代码如下:

<div style="max-width: 800px;">
  <div class="carousel-wrapper">
    <div class="carousel-slider">
      <div class="slides-track" id="slidesTrack">
        <div class="image-container">
          <a href="#"><img src="https://picsum.photos/id/10/200/85" alt="image1"></a>
          <a href="#"><img src="https://picsum.photos/id/11/200/85" alt="image2"></a>
          <a href="#"><img src="https://picsum.photos/id/12/200/85" alt="image3"></a>
        </div>
        <div class="image-container">
          <a href="#"><img src="https://picsum.photos/id/10/200/85" alt="image1"></a>
          <a href="#"><img src="https://picsum.photos/id/11/200/85" alt="image2"></a>
          <a href="#"><img src="https://picsum.photos/id/12/200/85" alt="image3"></a>
        </div>
      </div>
    </div>
  </div>
</div>
.carousel-wrapper {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
}

.carousel-slider {
  height: 100px;
  position: relative;
  overflow: hidden;
}

.slides-track {
  height: 100px;
  display: flex;
  align-items: center;
  /* 用JS控制transform,不需要CSS动画 */
  will-change: transform;
}

.image-container {
  display: flex;
  align-items: center;
}

.image-container img {
  height: 85px;
  padding: 0 8px;
}

.carousel-slider::before,
.carousel-slider::after {
  height: 100px;
  width: 50px;
  position: absolute;
  content: "";
  z-index: 2;
}

.carousel-slider::before {
  left: 0;
  top: 0;
  background: linear-gradient(to right, #fff 0%, rgba(255,255,255,0) 100%);
}

.carousel-slider::after {
  right: 0;
  top: 0;
  background: linear-gradient(to left, #fff 0%, rgba(255,255,255,0) 100%);
}
const track = document.getElementById('slidesTrack');
const singleContentWidth = track.firstElementChild.offsetWidth;
let offset = 0;
// 滚动速度:像素/帧,可根据需求调整
const speed = 1;
let rafId = null;

function scroll() {
  offset += speed;
  // 位移超过单份内容宽度时重置,实现无缝
  if (offset >= singleContentWidth) {
    offset = 0;
  }
  track.style.transform = `translateX(${-offset}px)`;
  rafId = requestAnimationFrame(scroll);
}

// 启动动画
rafId = requestAnimationFrame(scroll);

// 页面隐藏时暂停,避免无效渲染
document.addEventListener('visibilitychange', () => {
  if (document.hidden) {
    cancelAnimationFrame(rafId);
  } else {
    rafId = requestAnimationFrame(scroll);
  }
});

两种方案都需要保证两份滚动内容完全一致,这是无缝滚动的核心基础,重置位移时不会产生任何视觉跳变。

内容的提问来源于stack exchange,提问作者Parit Sawjani

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 12:36:19