CSS Scroll-Driven Animations

CSS scroll-driven animations connect a keyframe animation to scroll position or element visibility instead of elapsed time. As you scroll forward, the animation advances. When you scroll backward, it reverses.

This feature can create reading progress bars, reveal effects, and other scroll-linked interfaces without a JavaScript scroll listener. It builds on normal CSS @keyframes, so you define the visual change first and then choose its timeline.

Scroll and View Timelines

Timeline Progress Source Common Use
Scroll progress Position within a scrollable range Page progress bars and parallax effects
View progress Element movement through a scrollport Reveals and entry effects

You can create an anonymous scroll timeline with scroll() or an anonymous view timeline with view(). Named timelines are useful when the scroller and animated element are separated in the document.

Create a Reading Progress Bar

First, create a fixed bar and a keyframe that expands it from left to right. Then attach the animation to the root scroller with animation-timeline: scroll(root block).

Example:

<div class="progress" aria-hidden="true"></div>

<style>
.progress {
  position: fixed;
  inset: 0 0 auto;
  height: 8px;
  background: #2563eb;
  transform: scaleX(0);
  transform-origin: left;

  /* Link progress to the root page scrollbar. */
  animation: grow-progress linear;
  animation-timeline: scroll(root block);
}

@keyframes grow-progress {
  to { transform: scaleX(1); }
}
</style>

The block axis follows the page's block direction, which is vertical in the usual horizontal writing mode. The timeline maps the start of the scroll range to 0% and the end to 100%.

Reveal an Element with a View Timeline

A view timeline tracks a subject as it enters and leaves its scroll container. Attach view() directly to the element you want to animate.

Example:

.feature-card {
  /* Keep both starting and ending keyframe styles. */
  animation: reveal linear both;
  animation-timeline: view(block);
  animation-range: entry 10% cover 35%;
}

@keyframes reveal {
  from {
    opacity: 0;
    transform: translateY(40px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

Limit the Animation Range

The animation-range property controls which part of a timeline drives the animation. In the previous example, the effect begins shortly after the card starts entering and finishes after the card covers 35% of the scrollport.

  • entry covers the period in which the subject enters the scrollport.
  • contain covers positions where the subject is fully contained.
  • cover spans from first contact until the subject completely leaves.
  • exit covers the period in which the subject exits.

Use a Named Scroll Timeline

Name a timeline when an ancestor supplies the scrolling but another descendant uses its progress.

Example:

.product-list {
  height: 320px;
  overflow-y: auto;

  /* Create a named timeline on this scroller. */
  scroll-timeline: --product-scroll block;
}

.product-list .status-bar {
  animation: fill linear;
  animation-timeline: --product-scroll;
}

@keyframes fill {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

Respect Reduced Motion

Scroll-linked movement can make some users uncomfortable. Disable nonessential effects when the operating system requests reduced motion.

Example:

@media (prefers-reduced-motion: reduce) {
  .feature-card,
  .progress {
    /* Remove motion while keeping content available. */
    animation: none;
  }

  .progress {
    transform: scaleX(1);
  }
}

Browser Support and Fallbacks

Use @supports when the interface still needs a useful fallback. Keep content visible outside the support query, then enhance it when the browser understands scroll timelines.

Example:

.feature-card {
  opacity: 1;
}

@supports (animation-timeline: view()) {
  .feature-card {
    animation: reveal linear both;
    animation-timeline: view();
    animation-range: entry 10% cover 35%;
  }
}

Tip: Prefer animations of transform and opacity. They usually render more smoothly than layout-changing properties such as width, height, or top.

Conclusion

CSS scroll-driven animations let scroll position control standard keyframes. Use scroll() for progress through a scroller, view() for an element's journey through the viewport, and animation-range to choose the active segment. Always provide visible content and reduced-motion behavior.



Found This Page Useful? Share It!
Get the Latest Tutorials and Updates
Join us on Telegram