interactionbeginner

Scroll Progress Indicator

A bar (typically at the top of the page) that fills horizontally as the user scrolls down, visually communicating how far through a long document the reader has progressed.

Plain English

Long articles and documentation pages have a time-to-read uncertainty problem: the user does not know if they are 20% or 80% through without looking at the scrollbar, which is easy to miss or hidden on modern OSes. A scroll progress indicator solves this with a prominent colored bar that fills from left to right as you scroll down. It is a small affordance that reduces the psychological cost of committing to reading a long piece — you can see the finish line. It also doubles as a subtle branding element when colored with your primary accent. The native CSS version using scroll-driven animations is now just a few lines of code and requires no JavaScript at all.

Technical

JavaScript approach: on `scroll` event (throttled or passive), compute `scrollPercent = window.scrollY / (document.body.scrollHeight - window.innerHeight) * 100` and set `progressBar.style.width = scrollPercent + "%"`. Position with `position: fixed; top: 0; left: 0; height: 3–4px; z-index: 9999`. CSS-only scroll-driven animation (Chrome 115+, Safari 18+): `@keyframes progress { from { transform: scaleX(0); } to { transform: scaleX(1); } } .progress { position: fixed; top: 0; left: 0; right: 0; height: 4px; transform-origin: left; animation: progress auto linear; animation-timeline: scroll(); }`. The `animation-timeline: scroll()` ties the animation playback to the document scroll position — no JS needed. For browser support, provide the JS fallback inside `@supports not (animation-timeline: scroll())`. Avoid `overflow: hidden` on the `<html>` element — it breaks `scroll()` timeline. Use `will-change: transform` on the bar element for GPU compositing.

Live Demo

Scroll Progress Indicator

A thin bar at the top of the page fills as the user scrolls. Drag the slider to simulate scroll progress.

/article/design-systems

Design Systems Guide

0% read
0%

Modern CSS-only approach:

.progress-bar {
position: fixed; top: 0; left: 0;
height: 3px;
background: var(--accent);
transform-origin: left;
animation: progress-grow linear;
animation-timeline: scroll(root);
}

With CSS scroll-driven animations, no JavaScript is needed — the browser handles it natively.

Usage

✓ Good usage

A blog article page with a 3px primary-colored progress bar fixed to the top, implemented via CSS scroll-driven animation with a JS fallback — it appears only on article pages, not on the homepage or app screens where scroll position is irrelevant.

✗ Bad usage

Adding a scroll progress indicator to every page, including a login screen or a dashboard with multiple scroll containers — on short pages it snaps instantly to 100%, and on pages with inner scroll areas it tracks the wrong container.

Common mistakes

AI Prompt Example

Copy this into Claude, Cursor, Bolt, or v0.

Add a scroll progress indicator to all blog/article pages. Use CSS scroll-driven animation as the primary implementation: a fixed 4px div at `top: 0` with `transform-origin: left`, `animation: scaleX linear`, and `animation-timeline: scroll()`. For browsers that do not support scroll-driven animations, fall back to a JS passive scroll listener that computes `window.scrollY / (document.documentElement.scrollHeight - window.innerHeight)` and sets the bar width. Color the bar with the primary brand accent. Only mount the component on routes under `/blog`.