cssreactjsnext.jssasstailwind-css

How do I make my logo carousel with infinite scroll without any glitches? React and Tawilind


I’m working on a horizontal carousel component in React that uses CSS animations to create a seamless scrolling effect. While the carousel works as intended, I’m encountering a problem where the animation glitches when it resumes, causing a noticeable jump or stutter. I’m aiming for a smooth, continuous scroll without any interruptions.

React Component Code Here's the code for the React component handling the carousel:

import React from "react";
import ClienteLogo from "../ClienteLogo/ClienteLogo";

const ClienteLogos = [
  "./docebeijo.svg",
  "./find.png",
  "./logoa.png",
  "./logo.svg",
  "./logo.png",
  "./logob.svg",
  "./logo-magcom.png",
];

const ClientesSlider = () => {
  // Determina o número total de logos a serem exibidos
  const totalLogos = ClienteLogos.length;
  const logoWidth = 176; // Largura de cada logo + padding (44px + padding)
  const totalWidth = logoWidth * totalLogos;

  return (
    <div className="flex w-full justify-center overflow-hidden">
      <div
        className="flex animate-infinite-scroll flex-row gap-10 py-10"
        style={{
          width: `${totalWidth}px`, // Ajusta a largura total dos logos
          animationDuration: "20s", // Ajusta a duração da animação conforme necessário
        }}
      >
        {[...ClienteLogos, ...ClienteLogos].map((url, index) => (
          <ClienteLogo key={index} url={url} />
        ))}
      </div>
    </div>
  );
};

export default ClientesSlider;

Tailwind CSS Configuration And here's the configuration for Tailwind CSS:

/** @type {import('tailwindcss').Config} */
export default {
  content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
  theme: {
    extend: {
      keyframes: {
        "infinite-scroll": {
          "0%": { transform: "translateX(0)" },
          "100%": { transform: "translateX(-100%)" }, // Move para a largura total
        },
      },
      animation: { "infinite-scroll": "infinite-scroll linear infinite" },
    },
  },
  plugins: [],
};

Problem Description The issue arises when the carousel’s animation resumes. It causes a visible glitch, making the transition less smooth. I've tried various solutions from articles and guides, but none of them seem to resolve the problem. Here are some specific points:

Animation Jumps: The carousel seems to jump or stutter when the animation restarts. Seamless Loop: I want the carousel to scroll continuously without noticeable interruptions or jumps. Things I’ve Tried Adjusting animation duration. Modifying the width calculation. Using different Tailwind CSS configuration settings. Any advice or solutions to ensure a smooth, glitch-free carousel animation would be greatly appreciated!


Solution

  • You'd want to have the animation translateX() by exactly half the width of the space taken up by one "set" of the images. This also includes the gaps between them from gap-10.

    var(--count) * (theme(gap.10) + 176px) would be the space taken for one item (assuming from your code that each element is exactly 176px).

    We then double this for the container's width, since there are two sets of clones, w-[calc(2*var(--count)*(theme(gap.10)+176px))]. We ensure this is respected by setting flex-shrink: 0.

    Next, we ensure that the container starts from its left edge by removing the justify-center on the parent.

    Then, we set the animation to translateX(-50%), for one set of clones.

    const ClienteLogos = [
      "https://picsum.photos/176/100?./docebeijo.svg",
      "https://picsum.photos/176/100?./find.png",
      "https://picsum.photos/176/100?./logoa.png",
      "https://picsum.photos/176/100?./logo.svg",
      "https://picsum.photos/176/100?./logo.png",
      "https://picsum.photos/176/100?./logob.svg",
      "https://picsum.photos/176/100?./logo-magcom.png",
    ];
    
    const ClienteLogo = ({ url }) => <img src={url}/>
    
    const ClientesSlider = () => {
      // Determina o número total de logos a serem exibidos
      const totalLogos = ClienteLogos.length;
    
      return (
        <div className="flex w-full overflow-hidden">
          <div
            className="flex animate-infinite-scroll flex-row gap-10 py-10 w-[calc(2*var(--count)*(theme(gap.10)+176px))] shrink-0"
            style={{
              '--count': totalLogos, // Ajusta a largura total dos logos
              animationDuration: "5s", // Ajusta a duração da animação conforme necessário
            }}
          >
            {[...ClienteLogos, ...ClienteLogos].map((url, index) => (
              <ClienteLogo key={index} url={url} />
            ))}
          </div>
        </div>
      );
    };
    
    ReactDOM.createRoot(document.getElementById('app')).render(<ClientesSlider/>);
    
    /** @type {import('tailwindcss').Config} */
    tailwind.config = {
      theme: {
        extend: {
          keyframes: {
            "infinite-scroll": {
              "0%": { transform: "translateX(0)" },
              "100%": { transform: "translateX(-50%)" }, // Move para a largura total
            },
          },
          animation: { "infinite-scroll": "infinite-scroll linear infinite" },
        },
      },
      plugins: [],
    };
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.3.1/umd/react.production.min.js" integrity="sha512-QVs8Lo43F9lSuBykadDb0oSXDL/BbZ588urWVCRwSIoewQv/Ewg1f84mK3U790bZ0FfhFa1YSQUmIhG+pIRKeg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.3.1/umd/react-dom.production.min.js" integrity="sha512-6a1107rTlA4gYpgHAqbwLAtxmWipBdJFcq8y5S/aTge3Bp+VAklABm2LO+Kg51vOWR9JMZq1Ovjl5tpluNpTeQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
    <script src="https://cdn.tailwindcss.com/3.4.5"></script>
    
    <div id="app"></div>