20 CSS Image Sliders18 / 20

Pure CSSMIT licensed

Logo Marquee Endless Ticker

Logo marquee endless ticker — continuous crawl of client logos for B2B and agency sites, the classic Trusted by strip you see on Stripe, Vercel, Notion, Linear, and Shopify Plus landing pages. A dual-cloned track loops forever with one @keyframes and pauses on hover; grayscale by default, brand-color on hover. Zero JavaScript, seamless wrap, no visible loop seam.

Published

Live Demo
Try it

The code

<div class="cis-18">
  <p class="cis-18__label">Trusted by teams at</p>
  <div class="cis-18__stage">
    <div class="cis-18__track">
      <span class="cis-18__logo">NORTHWIND</span>
      <span class="cis-18__logo">Ampersand</span>
      <span class="cis-18__logo">LOOMLABS</span>
      <span class="cis-18__logo">Tidepool</span>
      <span class="cis-18__logo">VELA</span>
      <span class="cis-18__logo">Quanta·</span>
      <span class="cis-18__logo" aria-hidden="true">NORTHWIND</span>
      <span class="cis-18__logo" aria-hidden="true">Ampersand</span>
      <span class="cis-18__logo" aria-hidden="true">LOOMLABS</span>
      <span class="cis-18__logo" aria-hidden="true">Tidepool</span>
      <span class="cis-18__logo" aria-hidden="true">VELA</span>
      <span class="cis-18__logo" aria-hidden="true">Quanta·</span>
    </div>
  </div>
</div>
.cis-18,
.cis-18 *,
.cis-18 *::before,
.cis-18 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cis-18 ::selection {
  background: oklch(0.85 0.05 250);
  color: #0a0c14;
}

.cis-18 {
  --speed: 26s;
  --fade: 14%;
  --text: #c7ccdb;
  font-family: 'Segoe UI',system-ui,sans-serif;
  color: var(--text);
  width: 100%;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  background: linear-gradient(180deg,#0a0c12,#0e1119);
}

.cis-18__label {
  font: 700 11px ui-monospace,Menlo,monospace;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: #5c6377;
}

.cis-18__stage {
  width: min(920px,98vw);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg,transparent,#000 var(--fade),#000 calc(100% - var(--fade)),transparent);
  mask-image: linear-gradient(90deg,transparent,#000 var(--fade),#000 calc(100% - var(--fade)),transparent);
}

.cis-18__track {
  display: flex;
  align-items: center;
  gap: 64px;
  width: max-content;
  animation: cis-18-scroll var(--speed) linear infinite;
  will-change: transform;
}

.cis-18__stage:hover .cis-18__track {
  animation-play-state: paused;
}

.cis-18__logo {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -.01em;
  white-space: nowrap;
  color: var(--text);
  opacity: .62;
  transition: opacity .3s,color .3s;
  cursor: default;
}

.cis-18__logo:hover {
  opacity: 1;
  color: #fff;
}

@keyframes cis-18-scroll {
  from {
    transform: translateX(0);
  }

  to {
    transform: translateX(-50%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .cis-18__track {
    animation: none;
    flex-wrap: wrap;
    justify-content: center;
  }
}
/* No JavaScript — one @keyframes translateX(-50%) loop over a doubled logo track. */
Paste this into ChatGPT, Claude, Cursor, or any coding assistant. The block below is pre-framed with everything the AI needs to integrate this demo into your project — markup, styles, scoping notes, and the source URL. Hit Copy and paste straight into your chat.
Here's a working CSS Image Slider from CodeFronts. Use it as-is or adapt to your framework. All classes are scoped under a unique prefix so the code won't collide with your existing styles. MIT licensed.
Demo: Logo Marquee Endless Ticker
Source: https://codefronts.com/components/css-image-slider/logo-marquee-endless-ticker/

Logo marquee endless ticker — continuous crawl of client logos for B2B and agency sites, the classic Trusted by strip you see on Stripe, Vercel, Notion, Linear, and Shopify Plus landing pages. A dual-cloned track loops forever with one @keyframes and pauses on hover; grayscale by default, brand-color on hover. Zero JavaScript, seamless wrap, no visible loop seam.
## HTML
```html
<div class="cis-18">
  <p class="cis-18__label">Trusted by teams at</p>
  <div class="cis-18__stage">
    <div class="cis-18__track">
      <span class="cis-18__logo">NORTHWIND</span>
      <span class="cis-18__logo">Ampersand</span>
      <span class="cis-18__logo">LOOMLABS</span>
      <span class="cis-18__logo">Tidepool</span>
      <span class="cis-18__logo">VELA</span>
      <span class="cis-18__logo">Quanta·</span>
      <span class="cis-18__logo" aria-hidden="true">NORTHWIND</span>
      <span class="cis-18__logo" aria-hidden="true">Ampersand</span>
      <span class="cis-18__logo" aria-hidden="true">LOOMLABS</span>
      <span class="cis-18__logo" aria-hidden="true">Tidepool</span>
      <span class="cis-18__logo" aria-hidden="true">VELA</span>
      <span class="cis-18__logo" aria-hidden="true">Quanta·</span>
    </div>
  </div>
</div>
```
## CSS
```css
.cis-18,
.cis-18 *,
.cis-18 *::before,
.cis-18 *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

.cis-18 ::selection {
  background: oklch(0.85 0.05 250);
  color: #0a0c14;
}

.cis-18 {
  --speed: 26s;
  --fade: 14%;
  --text: #c7ccdb;
  font-family: 'Segoe UI',system-ui,sans-serif;
  color: var(--text);
  width: 100%;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 24px;
  background: linear-gradient(180deg,#0a0c12,#0e1119);
}

.cis-18__label {
  font: 700 11px ui-monospace,Menlo,monospace;
  letter-spacing: .3em;
  text-transform: uppercase;
  color: #5c6377;
}

.cis-18__stage {
  width: min(920px,98vw);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg,transparent,#000 var(--fade),#000 calc(100% - var(--fade)),transparent);
  mask-image: linear-gradient(90deg,transparent,#000 var(--fade),#000 calc(100% - var(--fade)),transparent);
}

.cis-18__track {
  display: flex;
  align-items: center;
  gap: 64px;
  width: max-content;
  animation: cis-18-scroll var(--speed) linear infinite;
  will-change: transform;
}

.cis-18__stage:hover .cis-18__track {
  animation-play-state: paused;
}

.cis-18__logo {
  font-size: 26px;
  font-weight: 800;
  letter-spacing: -.01em;
  white-space: nowrap;
  color: var(--text);
  opacity: .62;
  transition: opacity .3s,color .3s;
  cursor: default;
}

.cis-18__logo:hover {
  opacity: 1;
  color: #fff;
}

@keyframes cis-18-scroll {
  from {
    transform: translateX(0);
  }

  to {
    transform: translateX(-50%);
  }
}

@media (prefers-reduced-motion: reduce) {
  .cis-18__track {
    animation: none;
    flex-wrap: wrap;
    justify-content: center;
  }
}
```

## JavaScript
```js
/* No JavaScript — one @keyframes translateX(-50%) loop over a doubled logo track. */
```

How this works

The logo set is duplicated back-to-back inside a flex track, then animated from translateX(0) to translateX(-50%). Since the second half mirrors the first, the reset lands on an identical frame, so the loop is perfectly seamless. Edge mask-image fades logos in and out at the boundaries.

Only transform animates, keeping it on the compositor, and :hover pauses via animation-play-state. The cloned half is aria-hidden so screen readers hear each brand once.

Make it yours

  • Set crawl speed with --speed (larger = slower).
  • Reverse the direction with animation-direction: reverse.
  • Swap the text wordmarks for <img> logos — keep both halves identical.
  • Adjust edge fade width via --fade.

Gotchas — read before shipping

  • The item set must be duplicated exactly and the translate must be -50%, or the loop jumps.
  • Mark the cloned half aria-hidden="true" so assistive tech doesn't read duplicates.
  • If logos vary in width, use a fixed gap and let items size naturally — don't force equal widths.

Browser support

ChromeSafariFirefoxEdge
111+15.4+113+111+

Floor set by oklch() as this demo is written. The core technique itself goes back further — Chrome 85+.

transform animation + mask-image; supported in all current browsers.

Techniques used in this demo

Search CodeFronts

Loading…