A single element revealing itself as it scrolls into view is the simple case. Real production scroll storytelling usually needs several elements — possibly scattered across different parts of the DOM — moving in careful coordination with one underlying scroll event.
1Decoupling 'What's Tracked' From 'What Animates'
The default animation-timeline: view() is self-referencing — an element's own visibility drives its own animation. Real designs frequently need something more flexible: a sticky caption bar that should fade in as a *different* hero section (not itself) scrolls through view, for instance.
view-timeline-name: --hero-reveal assigns that hero section's visibility timeline an explicit, referenceable name. Any other element can then set animation-timeline: --hero-reveal to have its own animation driven by that named timeline, completely decoupling which element's scroll visibility is being tracked from which element's animation is actually playing.
2timeline-scope: Extending A Name Beyond Its Subtree
By default, a named view timeline is only referenceable by elements that are descendants of the element that declared view-timeline-name — a reasonable default that prevents naming collisions across unrelated parts of a large page, but one that also blocks a genuinely common need: a fixed sidebar or header, structurally outside the tracked section entirely, that still needs to react to that section's scroll visibility.
timeline-scope, declared on a shared ancestor of both the naming element and the element that needs to reference it, deliberately widens where that name is visible — extending the named timeline's reach to sibling subtrees that would otherwise have no access to it.
3Composing A Cohesive, Multi-Element Scroll Story
Combining named timelines and timeline-scope enables genuinely composed scroll narratives: a chapter heading that shrinks as its section scrolls through view, a table-of-contents indicator elsewhere on the page that highlights in sync with the same chapter, and a progress ring in a fixed corner all tied to that one chapter's visibility — every one of these elements driven by the exact same underlying named timeline, guaranteeing they stay perfectly synchronized to each other.
This is a meaningfully more maintainable approach than independently hand-tuning several separate scroll-triggered effects to *approximately* line up — with a shared named timeline, they're mathematically guaranteed to agree, because they're all reading from the same single source of truth.
4Step-by-Step Breakdown
Beyond A Single Element's Reveal. The Scroll-Driven Animations lesson introduced view() for a single element revealing itself. Real interfaces often need more: one element's animation driven by a *different* element's visibility, or several elements coordinated together into one cohesive scroll narrative — which is exactly what named view timelines and timeline-scope unlock.
Naming A View Timeline For Cross-Element Reference. view-timeline-name assigns an explicit name to an element's view timeline, which any other element (not just itself) can then reference via animation-timeline: --that-name — letting one element's animation be driven by a completely different element's scroll visibility.
Named View Timelines. What does naming a view timeline with view-timeline-name enable that the default, unnamed view() doesn't?
- →It makes the animation render measurably faster
- →It lets a different element (not just the one whose visibility is tracked) drive its animation from that timeline
- →It's required for any view() animation to function at all
timeline-scope: Extending Reference Beyond The Subtree. By default, a named timeline is only referenceable by descendants of the element that named it. timeline-scope, declared on a shared ancestor, extends that name's visibility so sibling subtrees — like a fixed sidebar entirely outside the section whose scroll position it should track — can also reference it.
timeline-scope's Purpose. Why would a named view timeline need timeline-scope declared on an ancestor to be usable by a sibling subtree?
- →It's never actually needed — named timelines work anywhere by default
- →By default, a named timeline is only referenceable within the descendants of the element that named it; timeline-scope extends that reach
- →It exists purely as a performance optimization with no functional effect
Orchestrating Multiple Elements Into One Scroll Narrative. Combining named timelines with timeline-scope lets a whole scroll-driven sequence be composed from independent, differently-timed pieces — a sticky caption that fades in as a hero section scrolls through view, a progress indicator elsewhere on the page tracking the same section — all driven by one shared, named timeline rather than each needing its own separate, disconnected tracking logic.
Orchestration Benefit. What's the advantage of driving multiple, differently-positioned elements from one shared named view timeline instead of giving each its own independent tracking logic?
- →It always produces less total CSS
- →Every element stays precisely synchronized to the same underlying scroll-visibility signal, rather than each independently approximating it
- →There's no real coordination benefit
View Timeline Orchestration Mastered. You can now name a view timeline for cross-element reference, extend that name's reach beyond its own subtree with timeline-scope, and orchestrate multiple, differently-positioned elements into one synchronized, cohesive scroll-driven narrative.
Alternate An Animation's Direction. animation-direction: alternate makes an animation reverse on every other iteration instead of resetting.
Level Up 🚀
Advanced cheat sheets, SEO tricks, and interview prep for this topic.
Browser Support
Fully supported.
Fully supported.
Fully supported.
Fully supported.
Accessibility (A11y)
1Orchestrated Multi-Element Scroll Effects Still Require A Complete prefers-reduced-motion Fallback
The more elements a scroll narrative coordinates, the more motion is potentially introduced simultaneously — verify the entire orchestrated sequence, not just individual pieces, is meaningfully reduced or disabled under prefers-reduced-motion.
2Cross-Element Animation Driving Should Never Be The Only Way Critical Information Is Conveyed
If a table-of-contents indicator's highlighted state is driven entirely by a named view timeline, ensure the same current-position information is also available through a non-visual, non-scroll-dependent mechanism for assistive technology users.
SEO Implications
- 1
Native Multi-Element Orchestration Avoids Multiple Independent JavaScript Scroll Listeners
Replacing several separate JS-driven scroll effects with one shared named CSS timeline reduces total main-thread scroll-handling code, compounding the performance benefit covered in the base Scroll-Driven Animations lesson across every coordinated element.
- 2
Guaranteed Synchronization Avoids Visual Inconsistency Bugs That Can Read As A Lower-Quality Experience
Independently-tuned JS scroll effects that drift slightly out of sync with each other can create a subtly unpolished feel; native timeline-driven synchronization eliminates that entire failure mode structurally.
Best Practices
Name A View Timeline As Soon As More Than One Element Needs To React To The Same Section's Scroll Visibility
Reaching for view-timeline-name and timeline-scope early avoids the temptation to hand-roll approximate JavaScript synchronization later, which is both more code and less reliably in sync.
Declare timeline-scope As Close To The Actual Shared Ancestor As Possible, Not At The Document Root By Default
Scoping it narrowly avoids unintentional naming collisions with unrelated named timelines elsewhere on a large page.
Frequent Bugs
An element referencing a named view timeline via animation-timeline: --name doesn't animate at all.
Check whether the referencing element is a descendant of the naming element, or whether timeline-scope has been declared correctly on a shared ancestor if it's a sibling subtree.
Two elements meant to be synchronized to the same scroll section drift slightly out of sync with each other.
They're likely using two separate, independently-configured view() timelines instead of one shared named timeline — consolidate them to reference the same view-timeline-name for guaranteed synchronization.
Real-World Examples
A Synchronized Table Of Contents Indicator
A long-form article where a fixed sidebar's table-of-contents highlight stays perfectly synchronized with which chapter is currently in view, using one named timeline per chapter shared between the chapter heading and its ToC entry.
.article { timeline-scope: --ch1, --ch2, --ch3; }
.chapter-1 { view-timeline-name: --ch1; }
.toc-item-1 { animation-timeline: --ch1; animation-name: highlight; }