Transitions & animation
The properties that change styles over time: transitions, which run when a value changes, and keyframe animations, which run from a set of @keyframes. This page also covers the properties that let discrete values and keyword sizes animate, and the names and classes used by view transitions. The @keyframes, @starting-style and @view-transition rules are under Other at-rules; easing functions such as cubic-bezier() and steps() are under Easing & timeline functions; animations driven by scrolling are under Scroll-driven animation.
Transitions
transition
Shorthand that makes property changes happen gradually instead of at once. Each comma-separated item names a property, a duration, an easing function, a delay and optionally allow-discrete.
| Syntax | <single-transition># |
|---|---|
| Initial | See individual properties |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 26 · Firefox 16 · Safari 9 |
| Spec | css-transitions-1 |
A <single-transition> is [ none | <single-transition-property> ] || <time> || <easing-function> || <time> || <transition-behavior-value>. The parts can come in any order, but the first time is always the duration and the second the delay. It sets transition-property, transition-duration, transition-timing-function, transition-delay and transition-behavior.
.button { transition: background-color 0.2s, scale 0.15s ease-out; }
.button:hover { background-color: navy; scale: 1.05; }
transition-property
Which properties transition when they change. A <single-transition-property> is all or a property name; none turns transitions off.
| Syntax | none | <single-transition-property># |
|---|---|
| Initial | all |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 26 · Firefox 16 · Safari 9 |
| Spec | css-transitions-1 |
The lists in the transition longhands pair up by position: the first property takes the first duration, the second the second, and so on. Shorter lists repeat to fill the gap.
transition-duration
How long each transition takes. The initial 0s means changes happen at once, so a transition only runs when a duration is set.
| Syntax | <time [0s,∞]># |
|---|---|
| Initial | 0s |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 26 · Firefox 16 · Safari 9 |
| Spec | css-transitions-1 |
transition-timing-function
The easing curve of each transition: how the value moves from start to end over the duration. See Easing & timeline functions for the values.
| Syntax | <easing-function># |
|---|---|
| Initial | ease |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 26 · Firefox 16 · Safari 9 |
| Spec | css-transitions-1 |
transition-delay
How long to wait after a value changes before its transition starts. A negative delay starts the transition straight away, part of the way through.
| Syntax | <time># |
|---|---|
| Initial | 0s |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 26 · Firefox 16 · Safari 9 |
| Spec | css-transitions-1 |
Animations
animation
Shorthand that runs one or more @keyframes animations on an element. Each comma-separated item can give a name, duration, easing, delay, iteration count, direction, fill mode and play state.
| Syntax | <single-animation># |
|---|---|
| Initial | See individual properties |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 43 · Firefox 16 · Safari 9 |
| Spec | css-animations-1 |
The parts can come in any order, but the first time is the duration and the second the delay. The shorthand also resets animation-timeline to auto without letting you set it, so write animation-timeline after animation.
@keyframes spin { to { rotate: 1turn; } }
.spinner { animation: spin 1s linear infinite; }
animation-name
The names of the @keyframes rules to run. Each name starts its own animation; the other animation longhands pair up with the names by position.
| Syntax | [ none | <keyframes-name> ]# |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 43 · Firefox 16 · Safari 9 |
| Spec | css-animations-1 |
A <keyframes-name> is an identifier or a string. A name that matches no @keyframes rule runs no animation.
animation-duration
How long one cycle of each animation takes. For a time-based animation auto means 0s; for a scroll-driven animation it means the animation fills its timeline.
| Syntax | [ auto | <time [0s,∞]> ]# |
|---|---|
| Initial | auto |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 43 · Firefox 16 · Safari 9 |
| Spec | css-animations-2 |
The auto keyword arrived later than the property: Chrome 115 · Firefox 159 · Safari 18.4.
animation-timing-function
The easing curve of each animation. It applies between each pair of keyframes, not across the whole animation, and a keyframe can set its own animation-timing-function for the segment that follows it.
| Syntax | <easing-function># |
|---|---|
| Initial | ease |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 43 · Firefox 16 · Safari 9 |
| Spec | css-animations-1 |
animation-delay
How long to wait before each animation starts. A negative delay starts the animation straight away, part of the way through, which is a simple way to stagger several copies of one animation.
| Syntax | <time># |
|---|---|
| Initial | 0s |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 43 · Firefox 16 · Safari 9 |
| Spec | css-animations-1 |
animation-iteration-count
How many times each animation runs: a non-negative number, which can be fractional to stop part way through a cycle, or infinite.
| Syntax | <single-animation-iteration-count># |
|---|---|
| Initial | 1 |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 43 · Firefox 16 · Safari 9 |
| Spec | css-animations-1 |
animation-direction
Whether each cycle plays the keyframes forwards or backwards.
| Syntax | <single-animation-direction># |
|---|---|
| Initial | normal |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 43 · Firefox 16 · Safari 9 |
| Spec | css-animations-1 |
| Value | Effect |
|---|---|
normal | Every cycle plays from from to to. |
reverse | Every cycle plays from to to from, with the easing reversed too. |
alternate | Odd cycles play forwards and even cycles backwards, so the animation swings back and forth. |
alternate-reverse | Like alternate, but starting backwards. |
animation-fill-mode
Whether an animation's keyframe styles apply outside the time it is running. forwards keeps the final keyframe after it ends, backwards applies the first keyframe during the delay, and both does both.
| Syntax | <single-animation-fill-mode># |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 43 · Firefox 16 · Safari 9 |
| Spec | css-animations-1 |
animation-play-state
Pauses (paused) or resumes (running) each animation. A paused animation holds its current frame and carries on from there when it is set running again.
| Syntax | <single-animation-play-state># |
|---|---|
| Initial | running |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 43 · Firefox 16 · Safari 9 |
| Spec | css-animations-1 |
animation-composition
How an animation's values combine with the underlying value of the same property. replace overrides it, add appends to it (a transform list is extended), and accumulate sums them (two translations become one longer translation).
| Syntax | <single-animation-composition># |
|---|---|
| Initial | replace |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 112 · Firefox 115 · Safari 16 |
| Spec | css-animations-2 |
animation-timeline
The timeline that drives each animation's progress. auto is the document's normal clock; a named timeline, scroll() or view() ties the animation to scrolling instead. See Scroll-driven animation.
| Syntax | <single-animation-timeline># |
|---|---|
| Initial | auto |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 115 · Firefox 159 · Safari 26 |
| Spec | css-animations-2 |
A <single-animation-timeline> is auto | none | <dashed-ident> | <scroll()> | <view()>. A <dashed-ident> names a timeline set up with scroll-timeline-name or view-timeline-name; none leaves the animation with no timeline, so it does not run.
Discrete & size interpolation
transition-behavior
Whether transitions also run for properties that animate discretely, such as display and content-visibility. With allow-discrete the value flips at a sensible point instead of at once; for display: none the box stays visible until the transition ends.
| Syntax | <transition-behavior-value># |
|---|---|
| Initial | normal |
| Applies to | All elements |
| Inherited | No |
| Animation | Not animatable |
| Support | Chrome 117 · Firefox 129 · Safari 17.4 |
| Spec | css-transitions-2 |
A <transition-behavior-value> is normal or allow-discrete. To animate an element in as it appears, give its starting styles in an @starting-style rule.
[popover] {
opacity: 0;
transition: opacity 0.2s, display 0.2s allow-discrete, overlay 0.2s allow-discrete;
}
[popover]:popover-open { opacity: 1; }
@starting-style { [popover]:popover-open { opacity: 0; } }
interpolate-size
Lets transitions and animations run between a length and a sizing keyword such as auto, min-content or fit-content. It is inherited, so setting allow-keywords on :root turns it on for the whole page.
| Syntax | numeric-only | allow-keywords |
|---|---|
| Initial | numeric-only |
| Applies to | All elements |
| Inherited | Yes |
| Animation | Not animatable |
| Support | Chrome 129 · Firefox no · Safari no |
| Spec | css-values-5 |
:root { interpolate-size: allow-keywords; }
.drawer { height: 0; overflow: clip; transition: height 0.3s; }
.drawer.open { height: auto; }
overlay
Whether an element is in the top layer, as open popovers and modal dialogs are. Only the browser sets it; you cannot change its value, but you can list it in a transition with allow-discrete so an element stays in the top layer until its closing transition has finished.
| Syntax | none | auto |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Discrete; between none and auto it stays auto for the whole transition |
| Support | Chrome 117 · Firefox no · Safari no |
| Spec | css-position-4 |
View transitions
view-transition-name
Gives an element its own snapshot in a view transition, so it animates separately from the rest of the page between the old and new states. Each name must be used by only one element at a time.
| Syntax | none | <custom-ident> |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Discrete |
| Support | Chrome 111 · Firefox 144 · Safari 18 |
| Spec | css-view-transitions-2 |
An element with the same name in the old and new state animates from one position and size to the other. The named group is styled through pseudo-elements such as ::view-transition-group(hero). The keyword match-element gives each element an automatic unique name (Chrome 137 · Firefox 144 · Safari 18.4).
.product-photo { view-transition-name: hero; }
::view-transition-group(hero) { animation-duration: 0.4s; }
view-transition-class
Adds one or more class names to an element's view transition pseudo-elements, so many named elements can share one set of styles. Select them with a class in the pseudo-element argument, such as ::view-transition-group(*.card).
| Syntax | none | <custom-ident>+ |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Discrete |
| Support | Chrome 125 · Firefox 144 · Safari 18.2 |
| Spec | css-view-transitions-2 |
The class has no effect without a view-transition-name on the same element.
view-transition-group
Where an element's view transition group sits in the tree of pseudo-elements. By default every group is a direct child of ::view-transition; nesting a group inside an ancestor's group lets the ancestor clip it or move it along with itself.
| Syntax | normal | contain | nearest | <custom-ident> |
|---|---|
| Initial | normal |
| Applies to | All elements |
| Inherited | No |
| Animation | Discrete |
| Support | Chrome 140 · Firefox no · Safari no |
| Spec | css-view-transitions-2 |
| Value | Effect |
|---|---|
contain | Named descendants nest their groups inside this element's group. |
nearest | This element's group nests inside the group of its nearest ancestor that has a view transition name. |
<custom-ident> | This element's group nests inside the group of the ancestor with that view transition name. |
normal | Nests only if an ancestor uses contain; otherwise the group stays at the top level. |
view-transition-scope
Marks an element as a scope for the view transition names inside it, for view transitions started on that element rather than on the whole document.
| Syntax | none | all |
|---|---|
| Initial | none |
| Applies to | All elements |
| Inherited | No |
| Animation | Discrete |
| Support | Chrome 147 · Firefox no · Safari no |
| Spec | css-view-transitions-2 |