The stats band — "1,200+ reviews, 17 regions, $4M claimed" — ships on every landing page, and the numbers are supposed to count up when you scroll to them. The traditional build is an IntersectionObserver arming a requestAnimationFrame loop with an easing function. Workable. Also now optional.
CSS learned to count. Register a numeric custom property with @property and the browser can transition it like any animatable value, while counter() renders it as an integer:
The Money Pattern
@property --n {
syntax: '<integer>';
initial-value: 0;
inherits: false;
}
.stat {
counter-reset: n var(--n);
transition: --n 2s ease-out;
}
.stat::after { content: counter(n); }
/* scroll-triggered: flip the value when the band enters view */
.in-view .stat { --n: 1200; }
The transition tweens --n from 0 to 1200 and counter() repaints the integer each frame — no JS animation loop, easing from the browser's curve, and prefers-reduced-motion handled with one media query that sets transition: none.
You still want one small IntersectionObserver to add .in-view when the band scrolls in — ten lines, fire-once. That's the split in Velocity X's free stat-ticker: CSS owns the animation, JS owns only the trigger.
The Catch
@property support is good in current browsers but not ancient ones — and the failure mode is graceful by construction: the property jumps instantly to its final value. Your stats show correctly without the count-up. That's the right fallback for decorative animation; never gate the number itself behind the animation working.
The real design trap isn't technical: counters that start at 0 on every scroll-past read as a gimmick by the second viewing. Fire once per page view. And thousand-separators need counter() tricks or a trailing unit span — "1200" reads worse than "1,200+", so the free component renders prefix/suffix as plain markup around the counting integer.
The Verdict
A counting number is decoration, and decoration should cost zero main-thread time. CSS counts, JS triggers, reduced-motion skips — the whole component. stat-ticker is free and MIT with source in the public repo, and the heavier chart-adjacent pieces live in Stats & Numbers.









