Utilities✨ Premium

Ruled Grid

Grid of eight key figures separated by lines that live in the gutters; each figure counts up from zero to its value as it comes into view.

CSSGap DecorationsDashboard

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Utilities has 43 effects, including 3 free. Explore the category →

3 usage examples

Ardisette sailing boat — “The crossing in figures” halfway through the online logbook — Ruled Grid example 1

① Ardisette sailing boat — “The crossing in figures” halfway through the online logbook

WhenThe reader scrolls down the story of an Atlantic crossing; when the grid reaches the screen, days at sea, stopovers, night watches and dolphin pods count up to their value, with the days-at-sea cell highlighted in green.
WhyThe count lands at the moment you reach the section: three weeks at sea sum up as a highlight of the story, not as one more table.
SettingsRoot across the whole scene (540 px: 4×2), inside a scrolling area; for the capture, the scene scrolls the logbook on the first pointer movement (or after 2.5 s). Badge relabelled “2026”, rgd-cell--hot on “Days at sea”, values written the same way in French and English.
Roulvane cycling app — summary shown after “Finish ride” — Ruled Grid example 2

② Roulvane cycling app — summary shown after “Finish ride”

WhenThe rider taps “Finish ride”: the summary slides up over the map and distance, climb, time, speeds, energy and stops count up to their value.
WhyThe count rewards the effort right as the ride ends, and the gutter lines keep eight measures readable at a glance.
SettingsThe grid stays hidden (display: none) until the click: the observer sees it appear and starts the counters. Root stretched to the sheet height (min-height: 0 in the scene), “Finished” badge, values in units that read the same in French and English.
Ovrendel C2 cargo bike — specification table on the product page — Ruled Grid example 3

③ Ovrendel C2 cargo bike — specification table on the product page

WhenBelow the photo and price, range, payload, weight, motor, battery, charging, assist and torque sit in a 4×2 grid; moving the mouse over a cell tints it and lifts it slightly.
WhyThin lines separate eight measures without weighing the page down, and the highlight helps you keep your place when comparing two values.
Settings540 px root under a 60 px product strip; hover highlight from the sold CSS, replayed by the capture mouse. The figures also count up on appearance, as everywhere.

How it works

The separators are neither cell borders nor extra elements. On Chrome and Edge 149 and later, the grid uses native gutter rules (CSS Gap Decorations): dashed column-rule, solid row-rule and rule-inset: -4px letting them overhang the grid edges by 4 px. Elsewhere, a fallback draws the same lines with the .rgd-grid::before pseudo-element: four 1 px background images placed exactly mid-gutter, computed from the --gap spacing. The @supports (row-rule: 1px solid red) block chooses between the two.

The root is a container (container: rgd / inline-size): above 520 px the grid has 4 columns on 2 rows, below that 2 columns on 4 rows, with the fallback lines recomputed for that layout. minmax(0, 1fr) columns never push the page wider.

The script creates one IntersectionObserver per root. As soon as a figure is 40 % visible, it counts from 0 to the data-final value in 0.9 s (easing out), keeping prefix, decimals and unit (“3.2%”, “+18%”, “$27k”), then shows the exact final text. Each figure counts only once. On hover, a cell gets a tint and rises by 2 px; the header badge pulses every 2.2 s.

Accessibility

  • Values in the HTML: each figure is written in full in the page (and in data-final); without script or with reduced motion, it shows straight away, with no counter.
  • Reduced motion: with prefers-reduced-motion: reduce, no counting, no badge pulse, no movement on hover.
  • Hover is decorative only: highlighting a cell helps follow a row with the mouse but adds no information; cells are not focusable, there is nothing to reach with the keyboard.
  • Structure: <section aria-label>, <h3> title, value in <strong> followed by its label; fill in an aria-label that describes your own table.
  • Counter and screen readers: during the 0.9 s count, the text changes; a reader announcing it at that moment would hear an intermediate value, which is one more reason to let reduced motion switch the count off.

Browser compatibility

Native rules: row-rule and rule-inset from Chrome and Edge 149, neither Firefox nor Safari (according to @mdn/browser-compat-data 8.1.8). Container queries: Chrome 105, Firefox 110, Safari 16. Measured in Chromium 151 (native rules), Firefox 153 and WebKit 26.5 (fallback): lines mid-gutter in 4×2 and 2×4, 390 px page with no horizontal scroll, counters of two copies independent.

Chrome 149+✓ Full, native rules (measured)
Chrome 105 to 148✓ Full with fallback lines
Firefox 110+✓ Full with fallback lines (measured)
Safari 16+✓ Full with fallback lines (measured in WebKit)
Edge 149+✓ Full, native rules
Mobile iOS 16+✓ Full with fallback lines

Without @container, the grid keeps 4 columns even when narrow: nothing overflows the page but labels get tight. Without IntersectionObserver, figures count as soon as the page loads. Without JavaScript, they show directly.

The code

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

index.html — structure
<div class="fx-0820-root">
  <section class="rgd-panel" aria-label="…">
    <header class="rgd-head">
      <h3>…</h3>
      <span class="rgd-badge">…</span>
    </header>
    <div class="rgd-grid">
      <div class="rgd-cell">
        <strong class="rgd-num" data-final="12,480">12,480</strong>
        <span class="rgd-key">…</span>
      </div>
      <!-- 8 cells; rgd-cell--hot on the one to stand out -->
    </div>
  </section>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Native lines (CSS — column-rule, row-rule, rule-inset inside @supports) Purple dashes at 55 %, solid line at 35 %, 4 px overhang at the edges Switch column-rule to solid for a stricter table, or use rule-inset: 8px for lines that stop 8 px short of the grid edges.
Fallback lines (CSS — .rgd-grid::before, two sets: 4×2 and 2×4) Same colours, 1 px Change the colours in both sets along with the native rules for an identical look everywhere.
Spacing (CSS — --gap on .rgd-grid) 22 px The fallback recomputes line positions from this variable: change it, not gap directly.
Two-column threshold (CSS — @container rgd (max-width: 519.98px)) Below a 520 px root With short labels, lower it to 440 px to keep 4 columns for longer.
Values (HTML — text and data-final of .rgd-num) 8 sample figures Write the same value in both places; the counter keeps whatever comes before and after the number (“+18%”, “$27k”, “4.8/5”).
Count duration and threshold (JS — 900 and threshold: .4) 0.9 s, at 40 % visible Lengthen to 1.5 s for staged figures; raise the threshold to 0.8 to count only once the grid is well in view.
Highlighted cell (HTML — rgd-cell--hot class) MRR in #22ffaa green Put it on your page's main figure, or remove it for a neutral grid.
Badge (HTML — .rgd-badge) “Live”, 2.2 s pulse Replace the text with a year, a status or a product name; remove animation if the badge signals nothing live.

FAQ

Those browsers do not support gutter rules yet: the fallback draws solid 1 px lines in the same place. The dashed style only applies to Chrome and Edge 149 and later.
No, once per figure, the first time it comes into view. To replay, reload the page or insert a new copy of the root and run the script again.
The code fetches no data. If your script updates a figure, change its text and its data-final; the animated count does not replay, the new value simply shows.