An infinite logo marquee in pure CSS with a tiny vanilla JavaScript helper: two rows of customer logos glide in opposite directions, fade out at the edges and pause on hover. Use it as a "trusted by" strip under a hero, on pricing pages or anywhere you want social proof without taking much space.
How it works
The root section.lm-marquee contains a .lm-head with the heading and a .lm-toggle button, followed by two .lm-row elements. Each row wraps a .lm-track with one ul.lm-group of li.lm-logo items. A logo is an inline SVG mark plus a text name, so it scales crisply and is read out as text.
On DOMContentLoaded the script clones each .lm-group once, marks the copy aria-hidden="true" and adds .lm-animated to the root. In that state both groups sit side by side in the flex track and run the lm-scroll keyframes, which move each group left by its own width plus --lm-gap. When the first copy has scrolled out, the second one is exactly where the first started, so the loop has no seam. Every group has min-width: 100%, which prevents gaps on very wide screens. .lm-row--reverse plays the same animation backwards with its own duration, and a CSS mask fades the logos in and out at both edges.
Hovering a row sets animation-play-state: paused, and hovering a logo switches it from the neutral --lm-mono gray to its brand color. Without JavaScript nothing moves: the logos wrap into centered rows.
Customization
--lm-durationand--lm-duration-reverseon.lm-marquee: loop time of the first and second row; higher values scroll slower.--lm-gap: space between logos and between the two copies of a group;3.5remon phones and4.5remfrom 768px.--lm-fade: width of the edge fade, e.g.20%for a softer vignette or0%to turn it off.--lm-monoand--lm-bg: the resting logo color and the section background;.lm-cutshapes use--lm-bgto punch holes in the marks..lm-logo--blue,.lm-logo--roseand the other modifiers set--lm-brand, the hover color of a logo.- Replace the SVG and name inside any
.lm-logowith your own mark, or remove.lm-row--reverseto keep a single row.
Accessibility
Only the original groups are exposed to assistive technology; each ul.lm-group has an aria-label, and the clones are aria-hidden. SVG marks are decorative, so the company names are the accessible content. Because moving content that lasts longer than five seconds must be stoppable, the .lm-toggle button pauses both rows and reports its state with aria-pressed; it has a visible :focus-visible ring. With prefers-reduced-motion: reduce the script does not clone or animate anything, the toggle stays hidden and the logos are shown as a static, wrapped list.
Usage notes
Several marquees can share a page; each has its own toggle. Keep at least six logos per row so one group is wide enough for a smooth loop.