← All Examples

Scroll Spy Indicator

A reading progress bar that tracks scroll position using CSS scroll-driven animations.

Published May 19, 2026

Demo

Reading Progress

The Future of CSS

CSS has evolved dramatically over the past decade. What began as a simple styling language now supports animations, logical properties, and even scroll-driven effects.

Scroll-driven animations are one of the most exciting additions to the platform. They let you tie animation progress directly to a scroll position — entirely without JavaScript.

How It Works

The animation-timeline property accepts a scroll() function that references a scroll container. The browser maps the scroll range to the animation's progress.

A simple @keyframes that goes from width: 0% to width: 100% becomes a reading progress bar with a single CSS property.

Browser Support

Scroll-driven animations are supported in all modern evergreen browsers. No polyfill, no fallback JavaScript needed for the vast majority of users.

HTML

<div class="reading-bar"></div>
<article><!-- page content --></article>

CSS

.reading-bar {
  position: sticky;
  top: 0;
  width: 100%;
  height: 5px;
  background: #e0e0ea;
}

.reading-bar::after {
  content: "";
  display: block;
  height: 100%;
  background: linear-gradient(90deg, #5b4cdb, #e040fb);
  animation: reading-progress linear;
  animation-timeline: scroll(root block);
}

@keyframes reading-progress {
  from { width: 0%; }
  to   { width: 100%; }
}

How it works

animation-timeline:scroll() links an animation's progress to a scroll container. scroll(root block) tracks the page scroll; scroll(nearest block) tracks the nearest scrollable ancestor. The @keyframes simply go from width:0 to width:100%. The browser drives the animation position based on scroll — no requestAnimationFrame needed.