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

如何优化JavaScript实现的ReviewsWrapper内div水平循环滚动动画卡顿问题

卡顿原因

  • setInterval 回调执行时机受主线程其他任务阻塞,时间精度不可控,且5ms的执行间隔远高于常规屏幕60fps刷新率对应的16.6ms单帧时长,会导致大量无效执行和丢帧
  • 每次调用getBoundingClientRect、scrollTo、调整DOM节点顺序都会触发浏览器重排,高频执行会大量占用主线程资源,直接引发卡顿

最优方案:纯CSS实现无缝滚动(推荐)

利用CSS动画跑在合成线程的特性,完全不占用主线程,流畅度最高。实现原理是复制一份相同的滚动内容,整体向左平移到第一份内容完全移出视口时重置动画,实现无缝循环。

修改后的完整代码

CSS

#ReviewsWrapper {
  position: relative;
  max-width: 100vw;
  overflow: hidden;
  -ms-overflow-style: none;
  scrollbar-width: none;
}
.scroll-content {
  display: flex;
  width: fit-content;
  animation: scroll 20s linear infinite; /* 20s是滚动一周的时长,可自行调整 */
}
.review {
  min-width: 300px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px;
  margin: 8px;
  background: yellow;
}
p {
  margin-left: 8px;
}
@keyframes scroll {
  0% {
    transform: translateX(0);
  }
  100% {
    transform: translateX(-50%);
  }
}
/* 可选:鼠标悬停暂停滚动 */
#ReviewsWrapper:hover .scroll-content {
  animation-play-state: paused;
}

HTML

在原来的容器里加一层scroll-content包裹所有review:

<div id="ReviewsWrapper">
  <div class="scroll-content">
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review ONE</p>
    </div>
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review TWO</p>
    </div>
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review THREE</p>
    </div>
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review FOUR</p>
    </div>
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review FIVE</p>
    </div>
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review SIX</p>
    </div>
    <!-- 复制一份相同的内容,也可以用JS动态生成 -->
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review ONE</p>
    </div>
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review TWO</p>
    </div>
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review THREE</p>
    </div>
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review FOUR</p>
    </div>
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review FIVE</p>
    </div>
    <div class="review">
      <img src="https://via.placeholder.com/150">
      <p>Review SIX</p>
    </div>
  </div>
</div>

如果不想手动复制内容,可以加一段极简JS动态复制:

window.addEventListener('load', () => {
  const content = document.querySelector('.scroll-content');
  content.innerHTML += content.innerHTML;
})

替代方案:优化原JS逻辑

如果必须用JS实现,可以把setInterval换成requestAnimationFrame,和浏览器刷新频率同步,减少重排触发次数,优化后逻辑如下:

const flavoursContainer = document.getElementById('ReviewsWrapper');
let first = document.querySelector('#ReviewsWrapper div');
let firstWidth = first.offsetWidth;
// 关闭滚动的平滑效果,避免默认动画冲突
flavoursContainer.style.scrollBehavior = 'auto';

function animate() {
  if (first.getBoundingClientRect().right <= 0) {
    flavoursContainer.appendChild(first);
    flavoursContainer.scrollLeft -= firstWidth;
    // 更新当前的第一个元素和宽度
    first = document.querySelector('#ReviewsWrapper div');
    firstWidth = first.offsetWidth;
  }
  flavoursContainer.scrollLeft += 1;
  requestAnimationFrame(animate);
}

window.addEventListener('load', () => {
  requestAnimationFrame(animate);
});

内容的提问来源于stack exchange,提问作者Matúš Rebroš

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 10:24:03