Vertical Marquee
A column of lines that rises gently inside a fixed-height window, in a continuous loop, stopping on hover or with a Pause button.
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
The .vtmq-viewport window is 120 px tall (--vtmq-window) and hides whatever overflows. Inside, the .vtmq-group list holds your lines, written once. The script compares the list's height with the window's and stacks below it as many duplicates as needed to keep the window full, even with only three lines or a window enlarged to 400 px.
The track rises by one list height, then the vtmq-scroll animation starts over: the line that reappears at the bottom is a duplicate, at the very spot of the original, so the loop never jerks. Speed is set in pixels per second in data-speed (20 by default, i.e. one 39 px line every 2 seconds); data-direction="down" makes the column go down.
Lines are centred (--vtmq-align also takes left and right); the old version stuck them to the left edge of the area. If line heights change (font loaded late, text wrapping in a narrow column), a ResizeObserver redoes the maths; if a script edits the list, the duplicates are rebuilt.
Accessibility
- Stopping: the column stays still while the mouse is over it, and the round Pause button (
aria-pressed) freezes it until the next click. That is what WCAG 2.2.2 asks for automatic motion lasting over 5 seconds. - Speech output: duplicates are marked
aria-hidden="true"; a screen reader announces the list of lines once, like any list (before the repair: twice). - Keyboard: a link inside a line only takes focus in the original list; the column then goes back to its starting position, stops and scrolls the window up or down to that link. It moves again once focus leaves.
- Reduced motion: under
prefers-reduced-motion: reduce, the column no longer moves on its own, shows only the original list and becomes a small area you scroll with a finger or a wheel; when the list overflows, the window also takes keyboard focus (Tab) and scrolls with the arrow keys. - Contrast: cyan #22d3ee on #0a0a0f reaches 10.9:1.
Browser compatibility
Vertical CSS animation (translateY towards a variable), 4.5 KB of commented JavaScript, no dependency. ResizeObserver: Chrome 64, Firefox 69, Safari 13.1; prefers-reduced-motion: Chrome 74, Firefox 63, Safari 10.1. Measured in Chromium 151, Firefox 153 and WebKit 26.5: window always full, hover and button stop the column, two independent columns on one page, 0 errors.
Without JavaScript, the window shows the list standing still and can be scrolled by hand. In Safari before 13.1 (no ResizeObserver), the number of duplicates is only recomputed when the browser window is resized.
The code
HTML structure to paste into your page (the CSS + JS come with your purchase):
<div class="fx-0189-root" data-speed="20" data-direction="up">
<div class="vtmq-band">
<div class="vtmq-viewport">
<div class="vtmq-track">
<ul class="vtmq-group" role="list">
<li>First line</li>
<li>Second line</li>
</ul>
</div>
</div>
<button type="button" class="vtmq-toggle" aria-pressed="false" aria-label="Pause"></button>
</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 |
|---|---|---|
Lines (HTML — the <li> of .vtmq-group) |
4 lines | Text, links, pills or small images, written once. The script makes the duplicates. |
data-speed |
20 | Pixels per second. Between 12 and 25 so a line can be read before it leaves. |
data-direction |
up | down: the column goes down. |
--vtmq-window |
120px | Height of the visible window. |
--vtmq-align |
center | Line alignment: left, center or right. |
--vtmq-color / --vtmq-size / --vtmq-space |
#22d3ee / 1.25rem / 1rem | Colour, text size and space between two lines (the same at the seam). |
--vtmq-height / --vtmq-bg / --vtmq-padding |
180px / #0a0a0f / 1rem 0 | Demo frame; auto, transparent and 0 to fit it into a card. |
--vtmq-button / --vtmq-button-size |
rgba(255, 255, 255, .8) / 2rem | Colour and size of the Pause button. |
FAQ
@keyframes written for a fixed number of lines.aria-pressed). Only the hover stop ends when the mouse leaves.