← All effects

Scroll Progress

ScrollVanilla JS · zero dependenciesOne number: scrolled / scrollable
0

A long read

Scroll this window and watch the bar and the badge answer. Every scroll effect on this site starts from the same single number: how far you have scrolled, divided by how far you could.

Halfway there. The bar above is that number as a width; the ring is the same number as an arc length.

The colour shift you may notice is the number a third time — mapped onto a hue.

The end. 100% — and everything above agrees, because it is all one number.

scroll inside ↓
-- fps
prefers-reduced-motion detected — progress follows your scroll directly, no easing

X-ray · layers

the top edge line
circular % in the corner
hue travels with progress

Parameters

Bar thickness5 px
Smoothing0.25
Ring size56 px
Hue span120°
your version · updates as you tinker

How this effect works

Every scroll effect on this site is built on one number: progress = scrolled / scrollable, running 0 at the top and 1 at the bottom. This page is that number wearing three costumes at once: the bar is progress as a width, the ring is progress as an arc — a circle whose stroke-dashoffset shrinks as you read — and the colour shift is progress as a hue, drifting from violet toward pink as you approach the end.

The smoothing slider adds the one refinement worth having: instead of snapping to the target, the displayed value chases it with a small lerp each frame, so wheel clicks and touch flicks render as glides. Everything runs off the scroll event of this stage (your page would use the window), and nothing repaints unless you actually scroll.

Production notes: scroll-driven = user-driven, so prefers-reduced-motion keeps the indicators but drops the easing · reads scrollTop only in a passive scroll listener · the ring is inline SVG — no assets · the copied snippet is self-contained HTML + CSS + JS with its own demo scroll box.