CSS Scroll-Timeline and View-Timeline Explained

CSS scroll-driven animations revolutionize web interactions by decoupling keyframe animations from traditional time-based durations and tying them directly to scroll progress. Through the scroll-timeline and view-timeline specifications, developers can create complex, fluid scroll effects natively within CSS, removing the need for resource-intensive JavaScript scroll event listeners and significantly boosting rendering performance.

Understanding Scroll-Driven Animations

Traditionally, CSS animations run along a temporal timeline defined in seconds or milliseconds. The CSS Scroll-Driven Animations specification introduces progress-based timelines where 0% represents the start of a scroll container or element intersection, and 100% represents the end. Because these animations run natively in the browser's compositor thread, they do not block the main thread, effectively eliminating scroll jank and layout thrashing.

The scroll-timeline Specification

The scroll-timeline links animation progress to the overall scroll position of a scroll container (the scrollport). As the user scrolls through the container from top to bottom (or left to right), the animation advances linearly from 0% to 100%.

Key properties include:

  • scroll-timeline-name: Declares a custom identifier (e.g., --page-scroll) on the scroll container.
  • scroll-timeline-axis: Specifies the scroll direction to monitor (block, inline, y, or x). The default is block.
  • animation-timeline: Applied to the animated element, referencing the timeline name defined on the container.

Alternatively, developers can use the shorthand function scroll() directly on the animation-timeline property to target the nearest ancestor scroller or the root viewport without explicitly naming the container.

Primary Use Cases:

  • Reading progress bars indicating article completion.
  • Sticky navigation bars that shrink or change background color as the user leaves the top of the page.
  • Parallax background layers moving at variable rates relative to page scroll.

The view-timeline Specification

While scroll-timeline tracks the entire scroll container, view-timeline tracks an individual subject element's visibility as it enters, traverses, and leaves the visible scroll area (the scrollport).

Key features include:

  • view-timeline-name: Applied directly to the subject element being observed (e.g., --revealing-image).
  • view-timeline-axis: Specifies the scroll orientation, typically defaulting to block.
  • animation-range: Controls precisely when the animation starts and ends relative to the element's intersection with the scrollport. Ranges include entry (entering the view), exit (leaving the view), and cover (from entering to completely exiting).

Like scroll(), the shorthand function view() can be declared directly within animation-timeline on the animated element.

Primary Use Cases:

  • Revealing cards, images, or headings with fade-in and scale effects as they enter the screen.
  • Staggered list animations that trigger only when elements reach the viewport.
  • Exit animations that blur or rotate elements as they scroll out of view.

Practical Implementation

To create a global reading progress bar using scroll():

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

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

To reveal an image as it scrolls into view using view():

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

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

By leveraging scroll-timeline for container-level tracking and view-timeline for element-level intersection tracking, web developers can achieve precise, declarative, and high-performance interactive animations without relying on third-party JavaScript libraries.