
Marquee
A marquee that runs forever — built from your own elements, in any direction, at the same speed on every screen width.
An interaction runs over a fixed duration. The same path is longer on a 1440 screen than on a 390 one — up there the band races, down here it crawls. Here the width of your content is measured and the duration derived from it. The speed stays what you wrote down.
- WrapperThe visible cutout. Anything reaching beyond it is hidden.
- TrackIts children form one repetition. They are grouped and copied until the cutout is filled twice over.
- LoopThe track travels exactly one repetition. At the end the next copy sits where the first began — the seam is invisible.
Add this <script> to your project's custom code
Once per project is enough, even if you use the solution on several pages: Project Settings → Custom Code → Head Code. The script loads alongside the page without holding up rendering; it runs once the page is in place and does nothing while no fpu attribute is there.
<!-- FlowPowerUser · Marquee -->
<script defer src="https://cdn.jsdelivr.net/npm/@flowpoweruser/attributes@1/marquee.js"></script>Mark the cutout and the content
You need two elements, one inside the other. On the outside the wrapper — it limits what is visible and gets overflow: hidden automatically. Inside it the track, holding your elements side by side; a flex layout with a gap is the usual choice. Everything else happens on load: your elements move into a group, and that group is copied until the cutout is filled.
On the wrapperthe visible cutout
On the trackinside the wrapper
Marquee Wrapper fpu-marquee-element="wrapper"
└─ Marquee Track fpu-marquee-element="track"
├─ Logo 1
├─ Logo 2
├─ Logo 3
└─ Logo 4Publish and check
Publish the page and drag the browser window wider and narrower. Two things have to hold: the speed must not change, and nothing may jump or flash where the repetition starts over. If the band stands still, either the track has no content or the wrapper has no limited width — the console names both.
OptionalDirection, speed and pausing on hoverDefault: leftwards, 60 px/s
Without any setting the band runs leftwards at 60 pixels per second and never stops. All three values belong on the wrapper. For “up” and “down” the wrapper needs a limited height — otherwise it grows with its content and there is nothing left to hide.
On the wrapper
leftWhich way the band travels. For “up” and “down” the height is measured instead of the width. An unknown value falls back to “left” and writes a warning to the console.60Speed in pixels per second. Because the duration is derived from the measured length, this speed stays the same at every screen width. Values that are not numbers, or below one, fall back to 60.falseStops the band while the mouse is over it or something inside it holds keyboard focus. Only exactly “true” turns it on.OptionalA button to stop itfor accessibility
Movement that runs longer than five seconds and starts on its own needs a way to stop it, per WCAG 2.2.2. That is what this element is for. It manages aria-pressed itself and toggles on every click. One caveat: the button belongs in the wrapper or next to it — never inside the track, or it gets copied along.
On the button
OptionalSoft edges, spacing and draggingall optional
These four change nothing about the principle, only how the band feels. All of them belong on the wrapper.
On the wrapper
offFades the edges out so the elements do not look sharply cut off. “true” uses 48 pixels, a number sets the width yourself.0Extra spacing in pixels between two repetitions — added on top of any gap the track already has from the Designer.falseMakes the band grabbable with mouse or finger. A throw coasts out and blends back into the configured speed. Clicks on links inside stay clicks as long as the finger moves less than five pixels.falseWrites one line to the browser console on start: measured length, calculated duration and how many copies were made.Additional features
- Anyone asking for less motion gets none
- With “reduce motion” set in the operating system the band stands still — purely via CSS, no detour. The content then wraps normally instead of being cut off, so it stays fully readable.
- Change the width and it measures again
- Wrapper and track are observed. Drag the window, let images load in, or have a breakpoint change the layout, and the necessary copies are added and the duration recalculated.
- Your interactions stay intact
- The original elements are moved, not cloned — Webflow interactions on them keep working. Only the copies are clones, and those are hidden from screen readers and taken out of the tab order.
- Your own code can hook in
- The solution registers with the shared roof as soon as it runs. You can register beforehand as well — the callback arrives either way.