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

基于ReactJS与CSS实现无缝循环滚动动画的问题求助

React 无缝循环滚动动画解决方案

问题原因

  • 仅渲染单份列表内容,滚动到末尾后容器需从底部回滚到顶部,出现空白等待期
  • 动画起始位置使用100vw,与内容高度不匹配,导致滚动逻辑混乱

修复方案

核心思路

通过复制一份列表内容,让容器内存在两份完全相同的卡片,结合精准的动画滚动距离设置,实现滚动到第二份末尾时,第一份刚好衔接上,视觉上无空白无缝循环。

修改后的代码

React 组件代码(App.js)

import { useRef, useEffect, useState } from "react";
import Card from "./Card.js";
import "./styles.css";

const data = [
  { Name: "1" },
  { Name: "2" },
  { Name: "3" },
  { Name: "4" },
  { Name: "5" }
];

export default function App() {
  const containerRef = useRef(null);
  const contentRef = useRef(null);
  const [animationState, setAnimationState] = useState("paused");
  const [singleContentHeight, setSingleContentHeight] = useState(0);

  useEffect(() => {
    if (contentRef.current) {
      // 获取单份内容的实际高度
      const height = contentRef.current.offsetHeight / 2;
      setSingleContentHeight(height);
      setAnimationState("running");
    }
  }, []);

  // 渲染两份相同的卡片列表,实现无缝衔接
  const renderCards = [...data, ...data].map((el, index) => (
    <Card key={index} cardName={el.Name} />
  ));

  return (
    <div className="App">
      <div className="scroll-container" ref={containerRef}>
        <div 
          className="scroll-content" 
          ref={contentRef}
          style={{
            animationPlayState: animationState,
            "--scroll-height": `${singleContentHeight}px`
          }}
        >
          {renderCards}
        </div>
      </div>
    </div>
  );
}

CSS 代码(styles.css)

.App {
  overflow: hidden;
  height: 224px; /* 等于卡片高度+上下margin总和:200 + 12*2 */
}

.scroll-container {
  overflow: hidden;
  height: 100%;
}

.scroll-content {
  display: flex;
  flex-direction: column;
  animation: scrollVertical 5s linear infinite;
}

/* 使用CSS变量动态控制滚动距离,确保动画首尾衔接 */
@keyframes scrollVertical {
  0% {
    transform: translateY(0);
  }
  100% {
    transform: translateY(calc(var(--scroll-height, 0px) * -1));
  }
}

.card {
  width: 200px;
  height: 200px;
  background: #ffefef;
  box-shadow: 0px 1px 4px 1px rgba(158, 151, 151, 0.25);
  border-radius: 15px;
  margin: 12px;
  padding: 12px;
}

关键说明

  • 复制列表内容后,滚动容器内始终有一份完整的列表处于可视区域,另一份作为衔接补充
  • 动画滚动距离严格等于单份内容的高度,动画结束时容器刚好回到第二份内容的起始位置,也就是第一份内容的初始状态,实现无间隙循环
  • 使用CSS变量动态传递内容高度,避免硬编码数值,适配不同数量的卡片

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 01:04:59