The @keyframes
CSS at-rule is used to define the behavior of one cycle of a CSS animation.
Animations are similar to transitions in that they change the presentational value of CSS properties over time. The main difference is that while transitions trigger implicitly when property values change (for example, when a property value changes on hover), animations are explicitly executed when the animation properties are applied. Because of this, animations require explicit values for the properties being animated. These values are defined using animation keyframes specified in the @keyframes
rule. So, a @keyframes
at-rule is made up of an encapsulated set of CSS style rules that describe how the property values change over time.
Then, using the different CSS animation properties, many aspects of the animation can be controlled, including how many times the animation iterates, whether or not it alternates between the begin and end values, and whether or not the animation should be running or paused. An animation can also delay its start time.
To define an animation you have to start with the @keyframes
rule. A @keyframe
rule consists of the keyword “@keyframes“, followed by an identifier giving a name for the animation (which will be referenced using animation-name
), followed by a set of style rules (delimited by curly braces). The animation is then applied to an element by using the identifier as a value for the animation-name
property. For example:
/* define the animation */ @keyframes your-animation-name { /* style rules */ } /* apply it to an element */ .element { animation-name: your-animation-name; /* OR using the animation shorthand property */ animation: your-animation-name 1s ... }
What goes inside the curly braces of an @keyframes
rule?
Inside the curly braces, you define keyframes, or waypoints, that specify the values for the properties you’re animating, at certain points during the animation. This allows you to control the intermediate steps in a sequence of animations. For example, a simple animation @keyframe
may look like this:
@keyframes change-bg-color { 0% { background-color: red; } 100% { background-color: blue; } }
The ‘0%’ and ‘100%’ are keyframe selectors each of which defines a keyframe rule. The keyframe declaration block for a keyframe rule consists of properties and values.
The above animation is similar to a simple transition effect: the background color is animated from one value at the beginning of the animation (0%) till it reaches another value at the end of the animation (100%). The ‘0%’ and ‘100%’ keyframe selectors define the waypoints, or percentage points in time, that you want the animating properties to change values at. You can also use the selector keywords from
and to
instead of using 0% and 100%, respectively, as they are equivalent.
@keyframes change-bg-color { from { background-color: red; } to { background-color: blue; } }
A keyframe selector consists of one or multiple comma-separated percentage values or the from
and to
keywords. Note that the percentage unit specifier must be used on percentage values. Therefore, ‘0’ is an invalid keyframe selector.
The following is an example of an animation with keyframe selectors including multiple comma-separated percentage values and/or the keyword keyframe selectors from
and to
.
@keyframes bouncing { 0%, 50%, 100% { /* OR from, 50%, to */ top: 0; } 25%, 75% { top: 100px; } }
The above @keyframes
rule says that the element’s top offset will be equal to zero at the beginning, halfway though, and end of the animation, and that it will be equal to 100px quarter and three quarters of the way through; this means that the element is moving up and down several times through the animation cycle. The above declaration can also be written as follows:
@keyframes bouncing { 0% { top: 0; } 25% { top: 100px; } 50% { top: 0; } 75% { top: 100px; } 100% { top: 0; } }
Of course, when you have multiple same declaration blocks, it is useful to use the comma-separated list of keyframe percentages than repeat the blocks multiple times in a @keyframes
declaration.
You can animate multiple properties inside a keyframe rule and use multiple keyframes to specify an element’s property values at specific points in time.
For example, suppose you have an element that you want to animate from one position to another, horizontally. Using a CSS transition, you could move it from its initial to its final position, and have the browser calculate the intermediate positions so that the path from the initial to the final position is linear (a straight line). But, using an animation, you can have your element move in a non-linear path from the beginning to the end, by controlling its position at certain points in time during the animation. In the next example, we’re going to move an element from a start position to a final position in a triangular path, instead of a straight line.
@keyframes jump { 0% { left: 0; top: 0; } 50% { left: 200px; top: -200px; } 100% { left: 400px; top: 0; } } .element { position: relative; left: 0; top: 0; /* apply the animation to the element by calling its name here */ animation-name: jump; animation-duration: 3s; /* other animation controls */ }
What we did in the above @keyframes
is we controlled the movement of the element along the x-axis and along the y-axis using the left
and top
offset properties. We’ve moved the element by 400px to the right, and had it move 200px upwards halfway through (at 50%), before it moved back down at the end of the animation.
The following is the live demo of the above animation, showing the difference between the element being animated like this, and it being transitioned using a CSS transition:
View this demo on the Codrops PlaygroundYou can also take it further and have the element move in a full triangle path, thus making it move back to its initial position at the end of the animation:
@keyframes jump { 0%, 100% { left: 0; top: 0; } 33% { left: 200px; top: -200px; } 66% { left: 400px; top: 0; } }
You can also specify a set of keyframes without a ‘0%’ keyframe selector. If a ‘0%’ or from
keyframe is not specified, then the user agent constructs a ‘0%’ keyframe using the computed values of the properties being animated. If a ‘100%’ or to
keyframe is not specified, then the user agent constructs a ‘100%’ keyframe using the computed values of the properties being animated. If a keyframe selector specifies negative percentage values or values higher than 100%, then the keyframe will be ignored.
The keyframe declaration block for a keyframe rule consists of properties and values, as we have seen, that you want to animate. But, not all properties in CSS are animatable. If a non-animatable property is included in a keyframe rule, the property should be ignored (please see notes section below), with the exception of the animation-timing-function
property, which is not animatable, but will not be ignored, because it can be used inside a keyframe rule to specify the easing function used to animate the properties as they move to the next keyframe. For example:
@keyframes bounce { from { top: 100px; animation-timing-function: ease-out; } 25% { top: 50px; animation-timing-function: ease-in; } 50% { top: 150px; animation-timing-function: ease-out; } 75% { top: 75px; animation-timing-function: ease-in; } to { top: 100px; } }
In the above example, five keyframes are specified for the animation named “bounce”. Between the first and second keyframe (i.e., between ‘0%’ and ‘25%’) an ease-out
timing function is used. Between the second and third keyframe (i.e., between ‘25%’ and ‘50%’) an ease-in
timing function is used. And so on. The effect will appear as an element that moves up the page 50px, slowing down as it reaches its highest point then speeding up as it falls back to 150px. The second half of the animation behaves in a similar manner, but only moves the element 25px up the page. This animation results in a bouncing effect that can be used to simulate a bouncing ball animation. The following is a live demo using the above animation:
A timing function specified on the to
or ‘100%’ keyframe is ignored. See the animation-timing-function
property entry for more about animation easing functions.
The @keyframes
rule that is used by an animation will be the last one encountered in sorted rules order that matches the name of the animation specified by the animation-name
property. @keyframes
rules do not cascade; therefore, an animation will never derive keyframes from more than one @keyframes
rule.
To determine the set of keyframes, all of the values in the selectors are sorted in increasing order by time. If there are any duplicates (for example if you write two ‘50%’ keyframe rules and declaration blocks), then the last keyframe specified inside the @keyframes
rule will be used to provide the keyframe information for that time. There is no cascading within a @keyframes
rule if multiple keyframes specify the same keyframe selector values.
For example, in the following code snippet, only the second ‘30%’ keyframe rule will be used and hence only the styles provided in its declaration block will be applied. The styles provided in the first ‘30%’ keyframe will not be used.
@keyframes my-animation { from { /* styles here */ } 30% { /* 30% styles here */ } 30% { /* other 30% styles here */ } to { /* end styles here */ } }
If a property is not specified for a keyframe, or is specified but invalid, the animation of that property proceeds as if that keyframe did not exist. Conceptually, it is as if a set of keyframes is constructed for each property that is present in any of the keyframes, and an animation is run independently for each property.
For example:
@keyframes an-animation { from { left: 0; background-color: red; } 30%, 48% { left: 240px; } 60%, 85% { background-color: purple; } to { left: 500px; background-color: #009966; } }
The background-color
property is missing from the ‘30%’ and ‘48%’ keyframes, and the left
property is missing from the ‘60%’ and ‘85%’ keyframes. Hence, the background-color
property is animated using the ‘0%’ (from
), ‘60%’, ‘85%’, and ‘100%’ (to
) keyframes, and the left
property is animated using the ‘0%’, ‘30%’, ‘48%’, and ‘100%’ keyframes.
A property must be specified at least in both the ‘0%’ and ‘100%’ keyframes in order to be animated. Only properties that are specified in both the ‘0%’ and ‘100%’ keyframes will be animated; any property not included in both of those keyframes will retain its starting value for the duration of the animation sequence.
Trivia & Notes
Even though properties that are not animatable should be ignored as per the specification, browser behavior in this regard is non-consistent. Some properties that are stated as not animatable are still animated in some browsers. For example, changing the background image using background-image
inside an @keyframes
block, the background image is indeed changed and even animated in Chrome, but not in Firefox or IE, for example. The z-index
property is an animatable property, but using it inside an @keyframes
block you can’t see it animate. Some properties such as the display
property, are simply ignored and not applied at all when used inside the @keyframes
block. So keep that in mind when you use non-animatable properties in an animation. The specification is still unclear and not very consistent about this at this time. This entry will be updated as soon as it is.
Official Syntax
@keyframes <user-ident> { [ [ from | to | <percentage> ] [, from | to | <percentage> ]* block ]* }
The to
and from
keywords are equivalent to ‘100%’ and ‘0%’ respectively. The animation name, the @keyframes
identifier, is a custom identifier of the type <user-ident>
. See the <user-ident>
for a list of possible values and rules.
Examples
In the following example, we’re going to create a falling effect for a piece of text using CSS animations. The text will “swing” and fall down by rotating it using CSS transforms and then fading it out by animating its opacity.
In the keyframes set, we’re going to start with the initial position of the text, when it’s neither transformed nor faded out:
@keyframes fall { from { transform: rotate(0) translateX(0); opacity: 1; } /* ... */ }
We know that we want the text to be rotated by 90 degrees at the end of the animation, translated downwards and faded out..
@keyframes fall { from { transform: rotate(0) translateX(0); opacity: 1; } /* ... */ to { transform: rotate(90deg) translateX(200px); opacity: 0; } }
By specifying only these two keyframes, this is how the animation looks so far:
View this demo on the Codrops PlaygroundAs you can see, the fall doesn’t look very realistic. We need the text to rotate first so that it looks like it’s going to fall, by attaching only its left edge to the initial position, and then have it fall down (translate) and fade out from there. We need to control the intermediate steps of the animation, so we’ll specify the rotation and position of the text during the animation using more keyframes.
We want the element to rotate first, and then after rotating we can allow it to fall down by moving to the last keyframe directly. So we can add one more step (keyframe) where we rotate the element, but don’t translate it and don’t fade it out:
@keyframes fall { from { transform: rotate(0) translateX(0); opacity: 1; } 50%, 60% { transform: rotate(90deg) translateX(0); opacity: 1; } to { transform: rotate(90deg) translateX(200px); opacity: 0; } }
Depending on the effect you’re after, the intermediate keyframe can be at ‘50%’ or any other percentage. Sometimes all you have to do is experiment and play with the values to see how it changes the animation. And sometimes a little math can do. In this example, we expect the text to rotate before it falls down, stays a little bit in the “hanging” position, and then fall down. Here is the result of applying the intermediate keyframe to the animation:
View this demo on the Codrops Playground
We can make the effect more realistic by changing the speed and timing function by which each keyframe animates. We’re going to use the cubic-bezier()
timing function to specify a custom easing that adds a “swinging” effect to the text right before it falls down. We’ll add that timing function to the from
keyframe selector declaration block because we want it to be applied to the animation when the element is moving from its initial position to its rotated “hanging” position. Similarly, we’re also going to add a timing function to the animation between the intermediate and the final keyframes that makes the falling down appear faster and more realistic.
We’re also going to add one more keyframe at ‘85%’ to make the dropping and fading effect be applied earlier in the cycle, and a keyframe at ‘15%’ because otherwise the element will start the animation instantly and we wouldn’t be able to see its initial state. So our final @keyframes
looks like this:
@keyframes fall { from, 15% { transform: rotate(0) translateX(0); opacity: 1; animation-timing-function: cubic-bezier(.07,2.02,.67,.57); } 50%, 60% { transform: rotate(90deg) translateX(0); opacity: 1; animation-timing-function: cubic-bezier(.13,.84,.82,1); } 85%, to { transform: rotate(90deg) translateX(200px); opacity: 0; } }
The result of the above keyframe rules is the following. Try playing with the keyframe percentage values and easing functions to get a better feel of how the animation is controlled by them and how you can create your own effects.
View this demo on the Codrops PlaygroundLive Demo
In this live demo, we’ve created a shaking effect using @keyframes
. The position of the element is alternated between the left and right offsets at different keyframes. The second element is also shaked by the same animation, but, additionally, it is also rotated along the way. Play with the code and change the percentage values and speeds to see how the animation is affected.
Browser Support
CSS Animation
Complex method of animating certain properties of an element
W3C Working Draft
Supported from the following versions:
Desktop
- 43
- 16
- 10
- 12
- 9
Mobile / Tablet
- 9.0
- 130
- No
- 130
- 130