Scroll-driven animation
The properties that link animations to scrolling instead of the clock. A scroll timeline tracks how far a scroll container has scrolled; a view timeline tracks how far an element has moved through its scroll container's visible area. An animation picks a timeline with animation-timeline, which is listed with the other animation properties under Transitions & animation. The anonymous timeline functions scroll() and view() are under Easing & timeline functions. Timeline triggers, which start a normal time-based animation when scrolling reaches a point, are at the end of the page.
Scroll timelines
scroll-timeline
Shorthand that turns a scroll container into a named timeline: a name, then optionally the axis to track. Its progress goes from 0% at the start of the scroll range to 100% at the end.
| Syntax | [ <'scroll-timeline-name'> <'scroll-timeline-axis'>? ]# |
|---|---|
| Initial | See individual properties |
| Applies to | All elements |
| Inherited | No |
| Percentages | See individual properties |
| Animation | Not animatable |
| Support | Chrome 115 · Firefox 159 · Safari 26 |
| Spec | scroll-animations-1 |
.gallery { overflow-x: auto; scroll-timeline: --gallery inline; }
.gallery-progress { animation: grow linear both; animation-timeline: --gallery; }
scroll-timeline-name
The name of the scroll timeline an element defines. Names are dashed identifiers such as --page. The element itself and its descendants can then use the name in animation-timeline.
| Syntax | [ none | <dashed-ident> ]# |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 115 · Firefox 159 · Safari 26 |
| Spec | scroll-animations-1 |
scroll-timeline-axis
Which scroll direction a scroll timeline tracks: the block or inline axis of the writing mode, or the physical x or y axis.
| Syntax | [ block | inline | x | y ]# |
|---|---|
| Initial | block |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 115 · Firefox 159 · Safari 26 |
| Spec | scroll-animations-1 |
View timelines
view-timeline
Shorthand that makes an element the subject of a named view timeline: a name, then optionally the axis and the insets. The timeline tracks the element as it scrolls into view, across, and out of view in its nearest scroll container.
| Syntax | [ <'view-timeline-name'> [ <'view-timeline-axis'> || <'view-timeline-inset'> ]? ]# |
|---|---|
| Initial | See individual properties |
| Applies to | All elements |
| Inherited | See individual properties |
| Percentages | See individual properties |
| Animation | See individual properties |
| Support | Chrome 115 · Firefox 159 · Safari 26 |
| Spec | scroll-animations-1 |
A view timeline is divided into named ranges that animation-range can refer to: cover (from first appearing to fully gone), contain (while fully inside, or fully covering, the scrollport), entry and exit (crossing the start and end edges), and entry-crossing and exit-crossing.
view-timeline-name
The name of the view timeline an element defines, as a dashed identifier. The element and its descendants can then use the name in animation-timeline.
| Syntax | [ none | <dashed-ident> ]# |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 115 · Firefox 159 · Safari 26 |
| Spec | scroll-animations-1 |
view-timeline-axis
Which scroll direction a view timeline tracks: block, inline, x or y.
| Syntax | [ block | inline | x | y ]# |
|---|---|
| Initial | block |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 115 · Firefox 159 · Safari 26 |
| Spec | scroll-animations-1 |
view-timeline-inset
Moves the start and end edges of the area a view timeline treats as visible, inwards for positive values. Use it when a fixed header or footer covers part of the scrollport. auto uses the scroll container's scroll-padding.
| Syntax | [ [ auto | <length-percentage> ]{1,2} ]# |
|---|---|
| Initial | auto |
| Applies to | All elements |
| Inherited | No |
| Percentages | Relative to the matching dimension of the scrollport |
| Animation | By computed value type |
| Support | Chrome 115 · Firefox 159 · Safari 26 |
| Spec | scroll-animations-1 |
Attaching timelines
An animation follows a scroll or view timeline once animation-timeline names one, or uses scroll() or view(). The keyframes then map onto scroll progress instead of time, so the duration is left as auto and the easing is usually linear. Write animation-timeline after the animation shorthand, which resets it.
@keyframes grow { from { scale: 0 1; } to { scale: 1 1; } }
.reading-progress {
position: fixed;
inset: 0 0 auto;
height: 4px;
background: currentColor;
transform-origin: left;
animation: grow linear both;
animation-timeline: scroll(root block); /* the page's own scroll position */
}
animation-range
Shorthand for the part of the timeline an animation is attached to: where it starts and where it ends. Outside that range the animation is inactive, or filled according to animation-fill-mode.
| Syntax | [ <'animation-range-start'> <'animation-range-end'>? ]# |
|---|---|
| Initial | See individual properties |
| Applies to | See individual properties |
| Inherited | See individual properties |
| Percentages | See individual properties |
| Animation | See individual properties |
| Support | Chrome 115 · Firefox 159 · Safari 26 |
| Spec | scroll-animations-1 |
A range name on its own covers that whole range, so animation-range: entry means entry 0% entry 100%.
@keyframes fade-in { from { opacity: 0; translate: 0 2rem; } }
.card {
animation: fade-in linear both;
animation-timeline: view();
animation-range: entry;
}
animation-range-start, animation-range-end
The point on the timeline where the animation starts, or ends. normal is the start, or end, of the whole timeline; a length or percentage is measured along the whole timeline; a range name such as cover or contain, with an optional percentage, is measured within that range.
| Syntax | [ normal | <length-percentage> | <timeline-range-name> <length-percentage>? ]# |
|---|---|
| Initial | normal |
| Applies to | All elements |
| Inherited | No |
| Percentages | Relative to the named timeline range if one is given, otherwise to the whole timeline |
| Animation | Not animatable |
| Support | Chrome 115 · Firefox 159 · Safari 26 |
| Spec | scroll-animations-1 |
timeline-scope
Widens the reach of a named timeline. Normally a named scroll or view timeline can only be used by the element that defines it and its descendants; declaring the name on a shared ancestor lets any element inside that ancestor use it, such as a sibling of the scroller. all does this for every name in the subtree.
| Syntax | none | all | <dashed-ident># |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 116 · Firefox 159 · Safari 26 |
| Spec | scroll-animations-1 |
.layout { timeline-scope: --article; }
.article { overflow-y: auto; scroll-timeline: --article; }
.sidebar-progress { animation: grow linear both; animation-timeline: --article; }
Timeline triggers
A timeline trigger watches a scroll or view timeline and fires when it enters a range. The animation it controls then runs on its own clock, at its normal duration, instead of following the scroll position. A trigger is defined with timeline-trigger on one element and used with animation-trigger on the animated element. These properties ship in Chrome only.
timeline-trigger
Shorthand that defines a named timeline trigger: its name, its timeline, and the ranges in which it activates and stays active. The range part is an activation range, optionally followed by / and an active range.
| Syntax | none | [ <'timeline-trigger-name'> <'timeline-trigger-source'> [ <'timeline-trigger-range'> ]? ]# |
|---|---|
| Initial | See individual properties |
| Applies to | See individual properties |
| Inherited | See individual properties |
| Percentages | See individual properties |
| Animation | See individual properties |
| Support | Chrome 146 · Firefox no · Safari no |
| Spec | animation-triggers-1 |
timeline-trigger-name
The names of the timeline triggers an element defines, as dashed identifiers. animation-trigger refers to them by these names.
| Syntax | none | <dashed-ident># |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 146 · Firefox no · Safari no |
| Spec | animation-triggers-1 |
timeline-trigger-source
The timeline each trigger watches: a named scroll or view timeline, or an anonymous scroll() or view() timeline.
| Syntax | [ none | auto | [ <dashed-ident> | <scroll()> | <view()> ]+ ]# |
|---|---|
| Initial | auto |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 146 · Firefox no · Safari no |
| Spec | animation-triggers-1 |
timeline-trigger-activation-range
Shorthand for the part of the timeline that activates the trigger: when the timeline's progress enters this range, the trigger fires.
| Syntax | [ <'timeline-trigger-activation-range-start'> <'timeline-trigger-activation-range-end'>? ]# |
|---|---|
| Initial | See individual properties |
| Applies to | See individual properties |
| Inherited | See individual properties |
| Percentages | See individual properties |
| Animation | See individual properties |
| Support | Chrome 146 · Firefox no · Safari no |
| Spec | animation-triggers-1 |
timeline-trigger-activation-range-start, timeline-trigger-activation-range-end
The start, or end, of a trigger's activation range. The values work the same way as animation-range-start and animation-range-end.
| Syntax | [ normal | <length-percentage> | <timeline-range-name> <length-percentage>? ]# |
|---|---|
| Initial | normal |
| Applies to | All elements |
| Inherited | No |
| Percentages | Relative to the named timeline range if one is given, otherwise to the whole timeline |
| Animation | Not animatable |
| Support | Chrome 146 · Firefox no · Safari no |
| Spec | animation-triggers-1 |
timeline-trigger-active-range
Shorthand for the part of the timeline in which an activated trigger stays active. Making it wider than the activation range stops the trigger switching on and off when scrolling hovers near an edge.
| Syntax | [ <'timeline-trigger-active-range-start'> <'timeline-trigger-active-range-end'>? ]# |
|---|---|
| Initial | See individual properties |
| Applies to | See individual properties |
| Inherited | See individual properties |
| Percentages | See individual properties |
| Animation | See individual properties |
| Support | Chrome 146 · Firefox no · Safari no |
| Spec | animation-triggers-1 |
timeline-trigger-active-range-start, timeline-trigger-active-range-end
The start, or end, of a trigger's active range. They take the same values as the activation range longhands, plus auto.
| Syntax | [ auto | normal | <length-percentage> | <timeline-range-name> <length-percentage>? ]# |
|---|---|
| Initial | auto |
| Applies to | All elements |
| Inherited | No |
| Percentages | Relative to the named timeline range if one is given, otherwise to the whole timeline |
| Animation | Not animatable |
| Support | Chrome 146 · Firefox no · Safari no |
| Spec | animation-triggers-1 |
animation-trigger
Connects an element's animations to named triggers. Each item names a trigger with a dashed identifier, followed by the actions to take on the animation when that trigger changes state.
| Syntax | [ none | [ <dashed-ident> <animation-action>+ ]+ ]# |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 146 · Firefox no · Safari no |
| Spec | animation-triggers-1 |
Like the other animation longhands, the list pairs up with animation-name by position.
trigger-scope
Sets the scope of trigger names at an element, in the same shape as timeline-scope does for timeline names: a list of names, all, or none.
| Syntax | none | all | <dashed-ident># |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 146 · Firefox no · Safari no |
| Spec | animation-triggers-1 |