Motion tied to your finger.
The progress bar at the top of the box below is driven by
animation-timeline: scroll(self) — no JavaScript, no
scroll listener, no requestAnimationFrame.
Inside, each slide animates in via animation-timeline: view()
when it enters the viewport.
How the progress bar works
.scroll-progress {
animation: progress linear;
animation-timeline: scroll(self);
transform-origin: 0 50%;
}
@keyframes progress { to { transform: scaleX(1); } }
scroll(self) says "use my own scroll position as the
timeline" — at the top of the scroller the animation is at 0%, at the
bottom it's at 100%. view() works the same way but on
per-element visibility, so each slide's title can rise as the slide
enters view.
Safari shipped both timelines in 2024. On a browser that doesn't support them, the animation simply never advances and the page still works — the progress bar just stays at zero.