Prefer Scroll and View Timelines
SHOULD: Use a CSS Scroll or View Timeline (`animation-timeline: view()`/`scroll()`) for scroll-linked motion — the compositor advances it, so it stays locked to the scrollbar even while the main thread is busy. This is still input-driven motion (`animations-input-driven`): the scroll IS the input. IntersectionObserver is a one-shot trigger, not a timeline — it cannot scrub, ignores scroll speed, and snaps on scroll-up; keep it for visibility and pausing. Chromium + Firefox 144+ only (Safari flagged), so treat it as an enhancement and make the un-animated state readable.
Scroll-linked motion belongs on a CSS timeline, not on an observer that toggles a class once and cannot scrub
.reveal { animation: fade-up linear both; animation-timeline: view(); animation-range: entry 0% cover 40%; }Bad
Good
Why it matters
This is the constructive half of the ban on scroll listeners. `animation-timeline: view()` binds an animation's progress to an element's position in the scrollport instead of to time, and the compositor advances it — so it stays locked to the scrollbar even while the main thread is busy. The common alternative, IntersectionObserver plus a class toggle, is not the same thing: it is a one-shot trigger.
It fires at a single threshold, it cannot scrub, it plays at its own duration regardless of how fast you scrolled, and on scroll-up it either does nothing or snaps back. ibelick keeps IntersectionObserver for what it is actually good at — "use IntersectionObserver for visibility and pausing". Support is Chromium and Firefox 144+; Safari is still behind a flag, so treat the animation as an enhancement and make the un-animated state the readable one.