Gallery✨ Premium

Alternating Rows

Several stacked rows of words gliding in opposite directions, every other one to the right, with a single Pause button for the whole block.

CSSMulti-row

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

An agency's skills — two giant rows at the foot of the hero — Alternating Rows example 1

① An agency's skills — two giant rows at the foot of the hero

WhenOn the Plumerande agency home page, below the tagline and the figures (140 projects, 12 people), a black band crosses two 31 px rows: visual identity, websites, motion design one way, accessibility, design system, copywriting the other.
WhyThe opposite directions add rhythm without showing off, and six trades fit in the height of a button. Off-white and the brand orange alternate from row to row.
Settingsdata-speed="45", two rows, --almq-size: 31px, --almq-space: 40px, --almq-color-1: #f2f0ea, --almq-color-2: #ff4d2e, --almq-bg: transparent; separator dot added by the page stylesheet.
Pottery workshop keywords — three tiny rows at the foot of each card — Alternating Rows example 2

② Pottery workshop keywords — three tiny rows at the foot of each card

WhenIn the Grèsolie workshop calendar, each workshop card (date, title, spots left, “Sign up” button) ends with three 9.5 px rows in small capitals: techniques, objects, practicalities.
WhyA texture detail that recalls the grooves left by a potter's wheel, adding nothing urgent to read. Two cards side by side each keep their own block, rhythm and button.
Settingsdata-speed="22", three rows, --almq-size: 9.5px, --almq-space: 14px, earth colours (#9a6a4c, #b4532a, #6b7f5a), --almq-button-size: 18px, two blocks on the same page.
Stops on a coach line — outbound on one row, return on the other — Alternating Rows example 3

③ Stops on a coach line — outbound on one row, return on the other

WhenOn the page of Lunavère Coaches line 42 (Annecy ⇄ Thônes), below the line number and the “Buy a ticket” button, the blue row runs the stops to the right and the amber row brings them back to the left.
WhyThe direction of motion tells the direction of travel. The “Out →” and “← Back” labels on the left also spell it out for anyone who cannot see the motion.
Settingsdata-speed="30", data-direction="right" on the outbound row, "left" on the return row, --almq-size: 12.5px, --almq-space: 10px, --almq-color-1: #0b5cad, --almq-color-2: #b45309.

How it works

Each .almq-row is a complete band: its window, its track and its list, written once. By default odd rows head left and even rows right, at 50 px per second; data-direction="left" or "right" on a row forces its direction, and data-speed on a row gives it its own speed (one slow row, one fast: that used to be a separate catalogue effect, here it is a plain attribute).

The script handles rows one by one: it measures each row's list, adds its duplicates, then sets its duration so the speed in pixels per second holds. Two rows of different lengths therefore move at the same pace and neither leaves a gap, even 1,900 px wide, where the old version broke apart beyond 600 px.

The .almq-rows block reacts as one: the mouse resting anywhere on it stops every row, and so does the Pause button. Colours come from --almq-color-1 to --almq-color-3 and repeat every three rows.

Accessibility

  • Single Pause button: one <button> with aria-pressed for all rows, reachable with Tab; hovering the block also stops everything (WCAG 2.2.2).
  • One reading per row: each row is a list read once; its duplicates carry aria-hidden="true". Before the repair, the three rows were each read twice.
  • Row direction: direction is decorative and not announced; if it carries meaning (outbound and return, for instance), also write it as text next to the rows.
  • Reduced motion: under prefers-reduced-motion: reduce, every row stands still, without duplicates or button, and each one can be scrolled by hand; a row that overflows also takes keyboard focus (Tab) and scrolls with the arrow keys.
  • Links: a row link receiving keyboard focus holds the whole block still, brings the rows back to their start and slides its own row to it.

Browser compatibility

One CSS animation per row, direction flipped with animation-direction, 4.5 KB of commented JavaScript, no dependency. ResizeObserver: Chrome 64, Firefox 69, Safari 13.1. Measured in Chromium 151, Firefox 153 and WebKit 26.5: three full rows at 390, 800 and 1,900 px, hover and button stop all three, two independent blocks, 0 errors.

Chrome 74+✓ Full (measured)
Firefox 69+✓ Full (measured)
Safari 13.1+✓ Full (WebKit engine measured)
Edge 79+✓ Full (Chromium engine)
Mobile iOS 13.4+✓ Full (WebKit engine measured)
Android Chrome 74+✓ Full (Chromium engine)

Without JavaScript, rows stay still, each scrollable by hand. Without ResizeObserver, duplicates are only recounted when the window is resized.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0194-root" data-speed="50">
  <div class="almq-band">
    <div class="almq-rows">
      <div class="almq-row">
        <div class="almq-viewport">
          <div class="almq-track">
            <ul class="almq-group" role="list">
              <li>First word</li>
              <li>Second word</li>
            </ul>
          </div>
        </div>
      </div>
      <div class="almq-row">
        <div class="almq-viewport">
          <div class="almq-track">
            <ul class="almq-group" role="list">
              <li>Another row</li>
              <li>Other way</li>
            </ul>
          </div>
        </div>
      </div>
    </div>
    <button type="button" class="almq-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 / propertyDefaultEffect
Rows (HTML — the .almq-row elements) 3 rows As many rows as you like; each has its own list, written once.
data-speed (root or row) 50 Pixels per second; on a row, it overrides the root's.
data-direction (on a row) alternating left or right forces the row's direction.
--almq-color-1, -2, -3 #6366f1, #d946ef, #22d3ee Colour of each row, repeating every three rows.
--almq-size / --almq-space 1.25rem / 4rem Text size and gap between two items of a row.
--almq-height / --almq-bg / --almq-padding 180px / #0a0a0f / 1rem 0 Demo frame; auto, transparent, 0 to set it inside a card.
--almq-button / --almq-button-size rgba(255, 255, 255, .8) / 2rem Colour and size of the button that stops the whole block.

FAQ

No: hover and button act on the whole block so any row can be read. For separate stops, stack several .fx-0194-root roots holding one row each.
Add data-speed to the row: <div class="almq-row" data-speed="120"> runs at 120 px/s while the others keep the root's speed.
No. Each row is measured and filled separately; a two-word row and a ten-word row move at the same speed and both stay full.