Cylinder Marquee 3D
A CSS 3D drum built from your list: it spins on its own, takes a drag with inertia and stops on hover, on focus or with Pause.
Updated
This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Gallery has 44 effects, including 6 free. Explore the category →
3 usage examples



How it works
You write a plain <ul class="cmq-items"> list (at least three <li>). The script turns it into as many .cmq-face faces, set in a ring with rotateY(i × 360°/N) translateZ(r); the radius r = (width/2) / tan(π/N) is computed so the faces touch, whatever their number. The .cmq-drum parent keeps the 3D (transform-style: preserve-3d) and a 700 px perspective gives depth.
On every frame the drum turns at 54°/s (speed based on elapsed time) and each face gets an opacity and brightness that follow the cosine of its angle: the front face is crisp, back faces dim without disappearing. Dragging anywhere in the scene, with a mouse or a finger, spins the drum (0.35° per pixel); on release it keeps the gesture's momentum, then returns to cruising speed.
Hovering the scene or moving keyboard focus into it slows the drum to a stop. The Pause button freezes it; while paused, the ‹ › arrows appear and bring the next or previous face to the front, announced in an aria-live area. Each .fx-0832-root has its own drum, and the loop stops when the scene leaves the screen.
Accessibility
- Readable content: the
.cmq-itemslist stays in the page, visually hidden but read by screen readers; the 3D faces, which copy it, carryaria-hidden="true". The scene is a region witharia-roledescription="carousel"named byaria-label. - Stopping: hover and keyboard focus stop the rotation; the Pause button (
aria-pressed) freezes it until the next click (WCAG 2.2.2). - Reduced motion: under
prefers-reduced-motion: reduce, the drum never spins on its own; the ‹ › arrows are shown, each click turns one face (0.38 s transition) and announces its text. Dragging still works, without momentum: on release the drum settles on the nearest face. - Touch:
touch-action: pan-ylets the page scroll when the finger moves vertically; only a horizontal drag spins the drum.
Browser compatibility
CSS 3D transforms (preserve-3d, perspective), Pointer Events with setPointerCapture, IntersectionObserver (feature-tested). Measured on 2026-11-08 in Chromium and Firefox: 54°/s rotation, stop on hover, focus and button, two independent copies, arrows under reduced motion, finger drag at 390 px. Playwright's WebKit flattens 3D: rotation and controls work there, but the 3D rendering could not be checked for Safari.
Without transform-style: preserve-3d, an @supports rule lays the faces flat side by side. Without JavaScript, only the scene background shows and the list stays readable by screen readers.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0832-root" data-cmq-speed="54" data-cmq-face-w="120" data-cmq-face-h="88">
<div class="cmq-scene" role="region" aria-roledescription="carousel" aria-label="…">
<ul class="cmq-items">
<li>…</li>
</ul>
<div class="cmq-perspective" aria-hidden="true"><div class="cmq-drum"></div></div>
<div class="cmq-reflection" aria-hidden="true"></div>
<div class="cmq-glow" aria-hidden="true"></div>
<div class="cmq-vignette" aria-hidden="true"></div>
<button class="cmq-pause-btn" type="button" aria-label="…" aria-pressed="false">⏸</button>
<div class="cmq-nav">
<button class="cmq-nav-btn cmq-prev" type="button" aria-label="…">‹</button>
<button class="cmq-nav-btn cmq-next" type="button" aria-label="…">›</button>
</div>
<div class="cmq-live" aria-live="polite" aria-atomic="true"></div>
</div>
</div>
One-time payment, no subscription — the code is yours forever
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
Faces (HTML — <li> of .cmq-items) |
8 demo words | At least three items. Text and inline elements (<b>, a small <img>) are copied onto the faces; links are not clickable there (faces are hidden and out of the keyboard order). |
Speed (HTML — data-cmq-speed on .fx-0832-root) |
54 (degrees per second) | From 0 to 360. At 0, the drum only turns when dragged. |
Face size (HTML — data-cmq-face-w, data-cmq-face-h) |
120 × 88 px | The drum radius follows: more or wider faces make a bigger drum. |
Scene height (CSS — .cmq-scene and .cmq-perspective) |
300 px and 260 px | Override both heights for a low strip or a small pill. |
Depth (CSS — perspective of .cmq-perspective) |
700px | Lower = stronger 3D, higher = flatter drum. |
Colors (CSS — .cmq-face-inner, .cmq-label, .cmq-glow) |
Violet #a78bfa, background #0a0814 | Border, background and text glow of the faces, central glow; .cmq-reflection and .cmq-vignette can be hidden. |
FAQ
data-cmq-face-w or enlarge the scene so the drum is not clipped.overflow: hidden or filter set on .cmq-drum itself, or a parent with transform-style: flat between the perspective and the drum. Keep .cmq-perspective as the direct parent of .cmq-drum..cmq-live area announces its text. Under reduced motion, they are always shown.