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

Next.js+TailwindCSS滚动动画卡顿重置问题求助

问题分析与解决方案

问题根源

你遇到的卡顿、重置问题,核心原因是百分比位移无法实现无缝循环动画:当前动画从x:100%滚动到x:-100%,但元素总宽度与容器宽度不匹配,导致每次循环时动画跳回初始位置,视觉上表现为卡顿重置;同时重复列表的位移逻辑没有对齐,无法实现平滑衔接。

修复后的代码

"use client";
import { motion } from "framer-motion";
import { useEffect, useRef, useState } from "react";
import { FaAws, FaReact, FaPython } from "react-icons/fa";
import { SiNextdotjs, SiMongodb, SiDjango } from "react-icons/si";
import { DiHtml5, DiCss3, DiJavascript1 } from "react-icons/di";
import { RiTailwindCssFill } from "react-icons/ri";

const technologies = [
  { icon: <DiHtml5 />, name: "HTML" },
  { icon: <DiCss3 />, name: "CSS" },
  { icon: <RiTailwindCssFill />, name: "TailwindCSS" },
  { icon: <DiJavascript1 />, name: "JavaScript" },
  { icon: <FaReact />, name: "React.js" },
  { icon: <SiNextdotjs />, name: "Next.js" },
  { icon: <FaPython />, name: "Python" },
  { icon: <SiDjango />, name: "Django" },
  { icon: <SiMongodb />, name: "MongoDB" },
  { icon: <FaAws />, name: "AWS" },
];

const Scrool = () => {
  const [singleListWidth, setSingleListWidth] = useState(0);
  const singleListRef = useRef(null);

  // 获取单个技术列表的实际渲染宽度
  useEffect(() => {
    if (singleListRef.current) {
      setSingleListWidth(singleListRef.current.offsetWidth);
    }
  }, []);

  return (
    <section className="py-12">
      <div className="container mx-auto">
        <h2 className="text-3xl font-bold text-center mb-8">
          Technologies I Know
        </h2>
        <div className="relative overflow-hidden">
          {/* 隐藏容器,用于计算单个列表的宽度 */}
          <div
            ref={singleListRef}
            className="flex gap-2 whitespace-nowrap absolute opacity-0 pointer-events-none"
          >
            {technologies.map((tech, index) => (
              <div
                key={index}
                className="flex flex-col items-center p-2 w-32 h-32 flex-shrink-0"
              >
                <div className="text-4xl text-accent">{tech.icon}</div>
                <span className="text-lg text-center">{tech.name}</span>
              </div>
            ))}
          </div>
          <motion.div
            className="flex gap-2 whitespace-nowrap will-change-transform"
            initial={{ x: 0 }}
            animate={{ x: `-${singleListWidth}px` }}
            transition={{ 
              duration: 20, 
              ease: "linear", 
              repeat: Infinity,
              repeatType: "loop"
            }}
          >
            {/* 重复两次列表实现无缝衔接 */}
            {technologies.map((tech, index) => (
              <div
                key={index}
                className="flex flex-col items-center p-2 w-32 h-32 flex-shrink-0"
              >
                <div className="text-4xl text-accent">{tech.icon}</div>
                <span className="text-lg text-center">{tech.name}</span>
              </div>
            ))}
            {technologies.map((tech, index) => (
              <div
                key={index + technologies.length}
                className="flex flex-col items-center p-2 w-32 h-32 flex-shrink-0"
              >
                <div className="text-4xl text-accent">{tech.icon}</div>
                <span className="text-lg text-center">{tech.name}</span>
              </div>
            ))}
          </motion.div>
        </div>
      </div>
    </section>
  );
};

export default Scrool;

关键修改说明

  1. 动态获取列表宽度:添加隐藏容器计算单个技术列表的实际宽度,避免手动计算的误差,确保滚动距离完全匹配列表长度
  2. 无缝位移逻辑:将动画从x:0滚动到-${singleListWidth}px,滚动完第一个列表后,第二个列表刚好衔接,实现无断层循环
  3. 性能优化:添加will-change-transform提示浏览器提前优化动画性能,减少卡顿概率
  4. 明确循环类型:设置repeatType: "loop"确保动画始终正向循环,不会出现反向滚动的异常

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.20 14:35:18