CSS Scroll-Driven Animations: No JavaScript Required

A deep dive into the new CSS scroll-driven animations API — how to use animation-timeline, scroll(), and view() to create scroll-linked effects with pure CSS.

Scroll-driven animations have been one of the most requested CSS features for years. We’ve relied on JavaScript — Intersection Observer, GSAP ScrollTrigger, custom scroll listeners — to link animations to scroll position. That era is ending.

The new primitives

Two new functions power CSS scroll-driven animations:

  • scroll() — links an animation to the scroll position of a scroll container
  • view() — links an animation to the visibility of an element within a scroll container

Both are used as values for the animation-timeline property.

A simple progress bar

The classic scroll progress indicator, zero JavaScript:

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

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

Reveal on scroll with view()

Elements that animate in as they enter the viewport:

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

.card {
  animation: reveal linear both;
  animation-timeline: view();
  animation-range: entry 0% entry 30%;
}

The animation-range property is key — it controls which part of the element’s visibility journey triggers the animation. entry 0% entry 30% means “animate while the element goes from 0% to 30% visible.”

Browser support

As of early 2025, scroll-driven animations are supported in Chrome, Edge, and Samsung Internet. Firefox support is in progress behind a flag. For production use, always include a @supports check or a prefers-reduced-motion fallback.

@supports (animation-timeline: scroll()) {
  .progress-bar {
    animation: grow linear;
    animation-timeline: scroll(root);
  }
}

What this replaces

BeforeAfter
Intersection Observeranimation-timeline: view()
Scroll event + scrollTopanimation-timeline: scroll()
GSAP ScrollTrigger (basic)Both, depending on use case

For complex sequencing and pinning, JavaScript libraries still have their place. But for the majority of scroll-based visual effects — reveals, parallax, progress indicators — CSS now has you covered.