[ @sdxc/u/animation ]
timeline-scope
Applies the timeline-scope property, raising a named timeline's visibility to a common ancestor's subtree so animations outside the declaring element can resolve the name; the subtree still declares it.
import { timelineScope } from "@sdxc/u/animation";Quick reference
Every documented call, beside the CSS it emits.
| Call | CSS |
|---|---|
u.timelineScope("page-scroll") | css({ timelineScope: "--page-scroll" }) |
u.timelineScope("page-scroll", "hero-reveal") | css({ timelineScope: "--page-scroll, --hero-reveal" }) |
Examples
Basic example
Use timelineScope() on a common parent to let elements outside the scroll container use its named timeline. Scroll the box to fill the bar above it:
Paragraph 1. Scroll this box to drive the timeline.
Paragraph 2. Scroll this box to drive the timeline.
Paragraph 3. Scroll this box to drive the timeline.
Paragraph 4. Scroll this box to drive the timeline.
Paragraph 5. Scroll this box to drive the timeline.
Paragraph 6. Scroll this box to drive the timeline.
Paragraph 7. Scroll this box to drive the timeline.
Paragraph 8. Scroll this box to drive the timeline.
<div mix={[timelineScope("article"), vstack({ gap: 3, align: "stretch" })]}>
<div
mix={[
bs(2),
bg("brand.solid"),
transformOrigin("left"),
animation("progress", {
keyframes: { from: { scale: "0 1" }, to: { scale: "1 1" } },
duration: "auto",
easing: "linear",
timeline: "--article",
}),
]}
/>
<div mix={[scrollTimelineName("article"), scroll("y"), bs(40), ...]}>
<div mix={[...]}>
{[1, 2, 3, 4, 5, 6, 7, 8].map((n) => (
<p mix={[...]}>Paragraph {n}. Scroll this box to drive the timeline.</p>
))}
</div>
</div>
</div>Scoping several names
Pass several names, like timelineScope("left", "right"), to raise more than one timeline. Scroll either box to fill its bar:
Paragraph 1. Scroll this box to drive the timeline.
Paragraph 2. Scroll this box to drive the timeline.
Paragraph 3. Scroll this box to drive the timeline.
Paragraph 4. Scroll this box to drive the timeline.
Paragraph 5. Scroll this box to drive the timeline.
Paragraph 6. Scroll this box to drive the timeline.
Paragraph 1. Scroll this box to drive the timeline.
Paragraph 2. Scroll this box to drive the timeline.
Paragraph 3. Scroll this box to drive the timeline.
Paragraph 4. Scroll this box to drive the timeline.
Paragraph 5. Scroll this box to drive the timeline.
Paragraph 6. Scroll this box to drive the timeline.
<div
mix={[timelineScope("left", "right"), grid(), gridTemplate({ columns: "1fr 1fr" }), gap(3)]}
>
{["left", "right"].map((name) => (
<div
mix={[
bs(2),
bg("brand.solid"),
transformOrigin("left"),
animation(`progress-${name}`, {
keyframes: { from: { scale: "0 1" }, to: { scale: "1 1" } },
duration: "auto",
easing: "linear",
timeline: `--${name}`,
}),
]}
/>
))}
{["left", "right"].map((name) => (
<div mix={[scrollTimelineName(name), scroll("y"), bs(40), ...]}>
<div mix={[...]}>
{[1, 2, 3, 4, 5, 6].map((n) => (
<p mix={[...]}>Paragraph {n}. Scroll this box to drive the timeline.</p>
))}
</div>
</div>
))}
</div>Applying on a state
Wrap the call in a state utility to scope it to one selector.
u.hover(u.timelineScope("page-scroll"))Responsive design
Wrap the call in a container query to scope it to one width.
u.at("md", u.timelineScope("page-scroll"))Signature
u.timelineScope(...names: string[])