SiteTidy
HomeGuidesCSS Scroll-Driven Animations: Zero-JavaScript Scroll Effects and Reading Bars
Frontend

CSS Scroll-Driven Animations: Zero-JavaScript Scroll Effects and Reading Bars

Master CSS scroll-driven animations with animation-timeline: scroll() and view(). Build reading progress bars and reveal-on-scroll effects in pure CSS.

Published on April 1, 2026Updated June 23, 2026
CSS Scroll-Driven Animations: Zero-JavaScript Scroll Effects and Reading Bars

Historically, creating scroll-linked animationsβ€”such as a top reading progress bar, sticky header shrink effects, or elements that fade and scale in as they enter the viewportβ€”required attaching JavaScript window.addEventListener('scroll', ...) listeners or running requestAnimationFrame loops.

These JavaScript scroll listeners frequently caused scroll jank and high CPU consumption because they ran on the browser main thread.

CSS Scroll-Driven Animations connect standard @keyframes animations directly to the scroll progress of a container or the viewport, executed directly on the Compositor Thread at 120fps with zero JavaScript.


1. scroll() vs. view() Timelines

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ 1. animation-timeline: scroll()                             β”‚
β”‚    Driven by the scroll position of the entire page or      β”‚
β”‚    scroll container (0% at top, 100% at bottom).            β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚ 2. animation-timeline: view()                               β”‚
β”‚    Driven by an individual element's visibility as it       β”‚
β”‚    enters, crosses, and exits the viewport.                 β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

2. Recipe 1: Pure CSS Reading Progress Bar

Create a top reading progress bar with 3 lines of CSS:

<div class="reading-progress-bar"></div>
.reading-progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 4px;
  background: linear-gradient(90deg, #0284c7, #38bdf8);
  transform-origin: 0 50%;
  
  /* Link animation to page scroll timeline */
  animation: grow-progress auto linear;
  animation-timeline: scroll(root block);
}

@keyframes grow-progress {
  from { transform: scaleX(0); }
  to   { transform: scaleX(1); }
}

3. Recipe 2: Reveal Elements on Scroll with view()

Animate cards as they scroll into view:

.reveal-card {
  animation: fade-slide-in ease-out both;
  animation-timeline: view();
  animation-range: entry 20% cover 40%;
}

@keyframes fade-slide-in {
  from {
    opacity: 0;
    transform: translateY(40px) scale(0.95);
  }
  to {
    opacity: 1;
    transform: translateY(0) scale(1);
  }
}
  • animation-range: entry 20% cover 40%: Starts the animation when the element is 20% into the viewport and completes by 40% coverage.

4. Respecting prefers-reduced-motion

Always disable scroll-driven movement for users with vestibular sensitivities:

@media (prefers-reduced-motion: reduce) {
  .reading-progress-bar,
  .reveal-card {
    animation: none !important;
  }
}

Next Steps

Ready to audit your site?

Put this guide into practice immediately using our free tools.

Browse 180+ Free Tools