DEV Community

Mykolas Mankevicius
Mykolas Mankevicius

Posted on

Infinite horizontal scroll, vanilla CSS

I needed a horizontal scroll in vanilla CSS without javascript

I found a few examples but none of them there fully complete

The trick is to repeat the items 3 times, then uses grid and animation tricks

This is the end result, not you need a smaller screen to see the effect:

https://play.tailwindcss.com/oMbuTy0AT5

Here is the html

<div class="scroll-container relative grid h-16 w-full overflow-hidden whitespace-nowrap">
<div data-first class="scroll flex h-16 w-full items-center justify-around gap-8 whitespace-nowrap px-4 lg:!animate-none" >
    <!-- loop over the items you want to infinitely scroll -->
    {{ list }} 
    {{ svg :src="icon" class="h-16  w-auto shrink-0" }}
    {{ /list }}
</div>
<div class="scroll flex h-16 w-full items-center justify-around gap-8 whitespace-nowrap px-4 lg:hidden lg:animate-none">
    {{ list }}
    {{ svg :src="icon" class="h-16  w-auto shrink-0" }}
    {{ /list }}
</div>
<div data-last class="scroll flex h-16 w-full items-center justify-around gap-8 whitespace-nowrap px-4 lg:hidden lg:animate-none" >
    {{ list }}
    {{ svg :src="icon" class="h-16 w-auto shrink-0" }}
    {{ /list }}
</div>
<div class="fade pointer-events-none absolute inset-0 lg:hidden"></div>
</div>
Enter fullscreen mode Exit fullscreen mode

and here is the css needed:

  @keyframes first-loop {
    0% {
      transform: translateX(0);
    }
    100% {
      transform: translateX(-200%);
    }
  }

  @keyframes loop {
    0% {
      transform: translateX(100%);
    }
    100% {
      transform: translateX(-100%);
    }
  }

  .scroll-container {
    --time: 30s;
    --half-time: 15s;

    grid-template-rows: 1fr;
    grid-template-columns: 1fr;
    grid-template-areas: 'scroll-area';
  }

  .scroll {
    grid-area: scroll-area;
    animation: loop var(--time) linear infinite;
    transform: translateX(100%);

    &[data-first] {
      animation: first-loop var(--time) linear forwards;
      transform: translateX(0);
    }

    &[data-last] {
      animation-delay: var(--half-time);
    }
  }

  .fade {
    background: linear-gradient(
      90deg,
      #fff,
      transparent 30%,
      transparent 70%,
      #fff
    );
  }
Enter fullscreen mode Exit fullscreen mode

Short explanation

The data-first applies an animation from the start so that you don't get a loop that moves the first items to 100% which would lead to a gap in the first revolution.

Maybe someone knows a way to avoid the first revolution

Top comments (0)