Motion

Scroll-driven animations

Limited availability

Replaces: A scroll listener and an IntersectionObserver driving classes. An animation’s progress is tied to scroll position, off the main thread.

See it working

Scroll this box. The bar is driven by the scroll position, with no listener and no JavaScript.

Keep going.

A little further.

Nearly at the end.

Done. The bar is full.

The syntax

.progress {
  animation: grow linear both;
  animation-timeline: scroll(nearest block);
}
@keyframes grow { from { scale: 0 1; } to { scale: 1 1; } }
The demo’s full CSS
.dm-sda { position: relative; height: 170px; overflow-y: auto; padding: 0 14px 14px; border-radius: 10px; background: #fff; border: 1px solid #dfe2ea; }
.dm-sda-bar { position: sticky; top: 0; height: 5px; margin: 0 -14px 12px; background: #f05a28; transform-origin: 0 50%; scale: 1 1; }
.dm-sda p { margin: 0 0 56px; font-size: 14px; line-height: 1.5; color: #1c1f2a; }
@supports (animation-timeline: scroll()) {
  .dm-sda-bar { animation: dm-sda-grow linear both; animation-timeline: scroll(nearest block); }
}
@keyframes dm-sda-grow { from { scale: 0 1; } to { scale: 1 1; } }

For browsers without it

The animation lives inside @supports and the bar is simply full-width without it. A reading-progress bar is decoration: the page must work with it sitting still.