Logo Marquee — Free HTML CSS JS Infinite Scroll Snippet
Logo Marquee · Animations · Plain HTML, CSS & JS · Live preview
What's included
Features
About this UI Snippet
Logo Marquee — Seamless Infinite Brand Logo Scroller

The logo marquee is the "trusted by" strip on nearly every B2B landing page: a horizontal row of customer or partner logos that scrolls continuously and loops forever. This snippet builds it in plain HTML, CSS, and a few lines of vanilla JavaScript, with a seamless loop, grayscale-to-color hover, edge fades, and pause-on-hover — and uses lightweight inline SVG marks so there are no image requests.
A seamless CSS loop
The whole scroll is driven by one CSS keyframe: lmScroll translates the track to translateX(-50%) over its duration. The reason -50% produces an endless loop is duplication — JavaScript renders the brand set twice (set + set), so the track is exactly two identical halves. When the animation reaches -50%, the first half has scrolled completely off and the second half sits precisely where the first began, so the keyframe restart is invisible. No JavaScript runs per frame; the browser's compositor handles the motion efficiently.
Pacing tied to the logo count
Rather than hard-coding a duration, JavaScript sets animationDuration to BRANDS.length * 3.4 seconds. This keeps the perceived speed steady no matter how many logos you add — twice as many logos take twice as long, so each logo spends the same amount of time on screen. Add or remove brands and the pace stays natural without manual retuning.
Grayscale to color on hover
Each logo renders desaturated and slightly dimmed via filter: grayscale(1) and reduced opacity, which is the conventional "logo wall" treatment that keeps the strip calm and uniform. On hover, the filter drops to grayscale(0) and full opacity so the pointed-at brand pops into color — a small interaction that rewards exploration. The transition on both filter and color makes the shift smooth.
Pause on hover
The track's animation is paused whenever the marquee is hovered, using the pure-CSS rule .lm-marquee:hover .lm-track { animation-play-state: paused }. That lets a visitor stop the strip to read a specific logo without any JavaScript, then it resumes seamlessly when the cursor leaves.
Edge fades with a mask
To avoid logos hard-cutting at the container edges, a horizontal mask-image gradient fades the leftmost and rightmost 10% to transparent, so brands dissolve in and out rather than popping. It's a compositing effect with no overlay elements.
Data-driven, image-free logos
All brands live in a BRANDS array of name, inline SVG path, and color, and a logoHTML function builds each link. Using inline SVG keeps the marquee crisp on any display and avoids the layout shift and extra requests of bitmap logos. To use your real customers, replace the array entries — drop in their SVG marks or swap the SVG for an <img> — and the loop, pacing, and fades keep working.
Customizing it
Change the 3.4 multiplier for a faster or slower crawl, widen the gap between logos, adjust the mask percentages for a longer fade, or remove the grayscale treatment for full-color logos. To scroll the other direction, animate to translateX(50%) from a -50% start, or flip the row with flex-direction: row-reverse. Pair it with a testimonial wall or place it under a feature tabs showcase for a complete social-proof section.
Build with AI
Build, Understand, Optimize, and Extend It With AI
You do not have to guess why the duration is computed rather than fixed. Paste this snippet's HTML, CSS, and JS into an AI coding assistant like Claude and ask it to explain exactly why track.style.animationDuration is set to BRANDS.length times 3.4 seconds instead of a constant value, and how that interacts with the set + set duplication to keep each logo's on-screen time constant regardless of how many brands are in the array. The same assistant can help optimize it, for instance asking whether building the logoHTML string with string concatenation for a much larger brand list could be replaced with a DocumentFragment to reduce reflow cost on the single innerHTML write. It is also useful for extending the marquee: ask it to make individual logo links actually navigate somewhere without breaking the seamless loop, add a second counter-scrolling row beneath it, or generate the BRANDS array from a CMS response instead of a hardcoded list. Treat the code less like a finished artifact and more like a starting point for a conversation.
Prompt to recreate it
Copy this into your AI assistant of choice to build the effect from scratch, or as a jumping-off point for your own variant:
Build an infinite "logo marquee" in plain HTML, CSS, and a small amount of JavaScript (for data-driven rendering only, not per-frame animation).
Requirements:
- A data array of brand objects, each with a name, an inline SVG path/icon string, and a color, used to generate a list of anchor elements, each containing an inline SVG mark (colored from that brand's own color value) and a text label.
- Render that generated logo list into the track's innerHTML exactly twice back to back (a single set concatenated with itself), so the track contains two identical halves for a seamless loop.
- Animate the track purely with a CSS keyframe that translates it to translateX(-50%) on an infinite linear loop — no requestAnimationFrame, no per-frame JavaScript.
- Compute the animation's duration in JavaScript as a function of the brand count (e.g. count times a fixed seconds-per-logo constant) and apply it via the element's style property, so adding or removing brands automatically keeps each logo's on-screen dwell time consistent without manually retuning a duration.
- Each logo must render desaturated and dimmed by default using a CSS grayscale filter and reduced opacity, transitioning to full color and full opacity on hover.
- Apply a pure-CSS rule that pauses the scroll animation via animation-play-state when the marquee container is hovered, requiring no JavaScript event listeners.
- Apply a horizontal mask-image gradient on the outer marquee container so logos fade to transparent at the left and right edges instead of clipping abruptly.Want to tighten it up first? Run this prompt through the AI Prompt Studio to score it across 8 quality dimensions, catch anti-patterns, and tune the wording for Claude, ChatGPT, or Gemini before you paste it in.
Step by step
How to Use
- 1Paste HTML, CSS, and JSA row of brand logos scrolls smoothly and loops forever.
- 2Hover a logoIt brightens from grayscale to full color.
- 3Hover the stripThe whole marquee pauses so you can read a brand.
- 4Note the edge fadesLogos dissolve in and out at the left and right.
- 5Swap in your brandsReplace the BRANDS array with real logos or images.
- 6Tune the paceAdjust the duration multiplier and logo gap.
Real-world uses
Common Use Cases
Got questions?
Frequently Asked Questions
The track contains the logo set rendered twice, so it is two identical halves. Animating to translateX(-50%) scrolls exactly the first half off-screen, at which point the second half sits where the first started. The keyframe then restarts at 0, which looks identical, so the loop is seamless with no JavaScript per frame.
JavaScript sets animationDuration to the logo count times 3.4 seconds. Because both the distance and the duration scale with the number of logos, each logo spends the same time on screen regardless of how many there are, so the crawl speed feels identical whether you show six brands or sixteen.
A pure-CSS rule pauses the animation on hover: .lm-marquee:hover .lm-track sets animation-play-state to paused. No JavaScript is needed — moving the cursor over the strip freezes it, and leaving resumes the scroll exactly where it stopped.
Yes. The BRANDS array holds each logo's name, inline SVG, and color. Replace those entries with your customers' SVG marks, or swap the inline SVG for an <img> tag pointing at logo files. Inline SVG keeps the strip sharp on high-DPI screens and avoids extra network requests and layout shift.
Render the doubled logo list from your data and set the animation duration via an inline style based on the array length. The CSS keyframe and hover pause work as-is. In Tailwind, define the scroll keyframe in your config, apply animate-[scroll_26s_linear_infinite], and use the group-hover utility to pause on hover with a masked container for the edge fades.