CSS Animations Tutorial

This is a full syntax guide and interactive CSS animations tutorial for beginners. Use it as reference to learn the different parts of the CSS animations spec.

Browser performance has come a long way in the past 10 years. It used to be a lot more challenging to add interactive animations to web pages due to the potential for rendering and performance issues. But nowadays, CSS animations can be used much more freely and the syntax is generally much easier to learn compared to CSS features like grid or flexbox.

There are different features that are part of the W3C CSS animation specification. Some easier to use than others. This CSS keyframe animations tutorial will go through all the syntax, including each of the different properties. I’ll include interactive demos to help you grasp what’s possible with CSS animations.

The @keyframes syntax

Every CSS animation has two parts to it: One or more animation-* properties along with a set of animation keyframes that are defined using the @keyframes at-rule. Let’s take a look in detail at what goes into building a @keyframes rule set.

The syntax looks like this:

@keyframes moveObject {
  0% {
    transform: translateX(0);

  50% {
     transform: translateX(300px);

  100% {
    transform: translateX(300px) scale(1.5);

As shown here, the @keyframes at-rule includes three basic parts:

  • The @keyframes rule followed by a custom animation name
  • A set of curly braces wrapping all the keyframes
  • One or more keyframes, each with a percentage followed by a rule set surrounded by curly braces

In this first example of our CSS animations tutorial, I’ve defined my animation with the name moveObject. This can be any name I want, is case sensitive, and must abide by the custom identifier rules in CSS. This custom name must match the name used in the animation-name property (discussed later).

In my example, you’ll notice I used percentages to define each of the keyframes in my animation. If my animation includes keyframes that equal 0% and 100%, I can alternatively use the from and to keywords:

@keyframes moveObject {
  from {
    transform: translateX(0);

  50% {
     transform: translateX(300px);

  to {
    transform: translateX(300px) scale(1.5);

The following interactive CodePen uses the above syntax in a live example:

In the demo, I’ve included a button that resets the animation. I’ll explain later why this is needed. But for now, just know that this animation includes three keyframes that represent steps in this animation sequence: the start, the 50% step, and the end (i.e., 0%, 50%, and 100%). Each of these uses what’s called a keyframe selector along with curly braces to define the properties at that step.

Some things to note about the @keyframes syntax:

  • You can put the keyframe rule sets in any order you want, and the browser will still run them in the order determined by their percentage
  • You can omit the 0% and 100% keyframes and the browser will automatically determine these by the existing styles on the element being animated
  • If there are duplicate keyframes with different rule sets (e.g., two keyframes for 20% with a different transform value), the browser uses the last one
  • You can define multiple keyframes in a single keyframe selector with a comma: 10%, 30% { ... }
  • The !important keyword nullifies any property value so it should not be used on a property inside a keyframe rule set

👉 Now that you have a good understanding of the @keyframes syntax in this CSS animation tutorial, let’s take a look at the different animation properties that are defined on the element being animated.

The animation properties that we’re going to cover:

The animation-name property

As mentioned, every CSS animation you create has to have a name that appears in the @keyframes syntax. This name has to be the same name defined using the animation-name property.

Using the CSS from the previous demo, the syntax looks like this:

.box {
  animation-name: moveObject;

Again, the custom name that I’ve defined has to also exist as a name for a @keyframes at-rule — otherwise this name will do nothing. You can think of this like a function call in JavaScript. The function itself would be the @keyframes moveObject {} portion of the code, while the function call is animation-name: moveObject.

Some things to keep in mind about animation-name:

  • The initial value for animation-name is none, which means no keyframes are active. This can be used as a sort of ‘toggle’ to deactivate an animation.
  • Your chosen name is case-sensitive and can include letters, numbers, underscores, and hyphens.
  • First character in the name must be a letter or a hyphen, but only a single hyphen.
  • The name can’t be a reserved word like unset, initial, or inherit.

The animation-duration property

The animation-duration property, no surprise, defines the amount of time an animation takes to run once from start to end. This value can be specified in seconds or milliseconds, as shown below:

.box {
  animation-duration: 2s;

The above would be the equivalent to the following:

.box {
  animation-duration: 2000ms;

You can see the animation-duration property in action in the following CodePen demo. In this demo, you can choose how long you want the animation to last. Try entering various values in either seconds or milliseconds, then use the “Animate the Box” button to run the animation.

If you use a small number along with ms for the unit, you may not even notice any movement. Try setting a higher number if you’re using milliseconds.

Some notes on using animation-duration:

  • Negative values are invalid
  • The unit must be included, even if the duration is set to 0s (the initial value)
  • You can use fractional values (e.g., 0.8s)

The animation-timing-function property

The animation-timing-function, which is not as obvious in its meaning as the previous two properties, is used to define the manner in which the CSS animation progresses. That might not be the clearest explanation, but the syntax might help clarify.

The declaration looks like this:

.box {
  animation-timing-function: linear;

This property accepts the following keyword values:

  • ease (the initial value)
  • ease-in
  • ease-out
  • ease-in-out
  • linear
  • step-start
  • step-end

Most of the values are relatively easy to grasp by their names, but you can see how they differ by using the following interactive demo:

Use the select input to choose one of the seven keyword values. Note that the ease-* values ‘ease’ the animation in various ways. A linear value is consistent all the way through.

The animation-timing-function property also accepts the following functions:

  • cubic-bezier() – Accepts as arguments four number values, separated by commas
  • steps() – Accepts as arguments two values, a number and a “jump term,” separated by a comma

The keyword values step-start and step-end are equivalent to the values steps(1, jump-start) and steps(1, jump-end), respectively.

As for cubic-bezier(), the following interactive demo might help you understand the function a little better:

Notice the demo lets you set the four arguments in the cubic-bezier() function. Two of the arguments can be negative, and two are constrained to decimal values between 0 and 1. For a decent explanation of how these types of timing functions work, you can check out this article or this interactive tool.

The steps() function, on the other hand, accepts two arguments:

  • An integer representing equal “stops” along a single cycle of the animation.
  • An optional keyword called a “jumpterm” that determines whether the animation “holds” at specific intervals

Again, an interactive demo should help you grasp how these jumpterms work:

Try selecting an integer along with a jumpterm (or try it with no jumpterm) to see how the different keywords differ with different integer values. Apparently negative integers are permitted but I don’t see any difference between 0 and any negative value.

The animation-iteration-count property

In some cases, you’ll be happy if an animation runs once, but sometimes you want an animation to run multiple times. The animation-iteration-count property lets you do this by accepting a positive number representing the number of times you want the animation to run:

.box {
  animation-iteration-count: 3;

The initial value for animation-iteration-count is 1 but you can also use the keyword infinite (self-explanatory) or use a fractional value. A fractional value will run the animation part way through on the fractional run:

.box {
  animation-iteration-count: 3.5;

The above code runs through the animation three and a half times. That is, three full iterations followed by one final iteration that stops exactly halfway through.

This property is most useful when used in conjunction with the animation-direction property (discussed next), because an animation that runs from the beginning only is not extremely useful if it runs more than once.

You can try the demo below which allows you to select a fractional value for the iteration count, so you can see the effect:

The animation-direction property

As mentioned above in this CSS animations tutorial, the animation-direction property works nicely in conjunction with animation-iteration-count. The animation-direction property allows you to define which direction you want the animation to play. The syntax looks like this:

.box {
  animation-direction: alternate;

You can set the value as one of four keywords:

  • normal – The animation plays forwards on the first iteration (the default)
  • reverse – Animation plays backwards on the first iteration
  • alternate – The animation plays forwards on the first iteration then alternates on subsequent iterations
  • alternate-reverse – Same as alternate but plays backwards on the first iteration

You can try out the different values with different iteration counts using the interactive demo below:

The animation-play-state property

The animation-play-state property is not extremely useful in a static CSS environment but might come in handy when writing animations that are interactive via JavaScript or even CSS.

This property accepts two values: running or paused:

.box {
  animation-direction: paused;

By default, any given animation is in the “running” state. But you can use JavaScript to toggle the property’s value. You could even feasibly use an interactive CSS feature like :hover or :focus to change the animation to a “paused” state, which essentially freezes the animation wherever it is in the current iteration.

The interactive demo below has an animation running infinitely with two buttons to “pause” and “resume” the animation.

The animation-delay property

Some animations are designed to start animating immediately, whereas others could benefit from a slight delay before the first iteration. The animation-delay property allows you to accomplish this.

.box {
  animation-delay: 4s;

Like other time-based values, you can set the animation-delay to a value using seconds or milliseconds. You can also use fractional values.

It’s important to note that the delay occurs only on the first iteration, not each iteration. You can try this out using the interactive demo below:

The demo gives you the option to change the iteration value as well as the delay, so you can see that the delay doesn’t affect any subsequent iterations – only the first.

An interesting way of using this property is with a negative value. For example, using the demo above, try setting the animation-delay to -0.5s. You’ll notice the negative delay works almost like going forwards in a time machine – the animation begins part way through rather than at the beginning.

The animation-fill-mode property

The final longhand property that I’ll cover in this CSS animations tutorial is one that I used in the previous demo. You’ll notice that when the animation stops the final iteration, the box remains where it is. This is accomplished using animation-fill-mode.

.box {
  animation-fill-mode: forwards;

This property sets how an animation applies styles to the targeted element before and after its execution. That’s a little hard to grasp conceptually, so I’ll cover the meaning of each value; then you can compare the values using the interactive demo.

This property accepts the following four keyword values:

  • none – The default, no styles applied before or after execution
  • forwards – Retains all styles applied in the last keyframe of the animation
  • backwards – More or less the reverse of the previous value, it retains styles applied to the animation as soon as it begins execution but before the animation begins
  • both – Retains styles for both forwards and backwards

The final demo in this CSS animations tutorial will make things a little clearer, but this one might take a lot of playing around before you really get what it does and how it achieves it.

For convenience, I’ve added all the demos into a single CodePen Collection.

You’ll notice that the demo lets you adjust the fill mode, delay, direction, and number of iterations, as all of these can have an effect on the appearance. I’ve also added a different background color to the animated box in the first keyframe, which again helps to make the fill mode values a little more clear. If you still don’t quite get how animation-fill-mode works, you can check out an older article I wrote that discusses animation-fill-mode in-depth.

The animation shorthand property

I’ve covered eight different properties in this CSS animation tutorial for beginners and I encourage you to use the long hand. This will make it easier for you to see the explicit values set.

Once you have a good understanding of each of the properties, you have the option to use the animation shorthand property, which lets you define all the longhand properties in a single declaration.

.box {
  animation: moveObject 2s ease-in-out 3 reverse running 1.3s forwards;

In all honesty, that’s a lot of information in a single line. I would recommend using the shorthand if the declaration doesn’t include all the properties, but maybe only three or four of them.

If you do use the shorthand, you can put the values in any order you want, but note the following rules:

  • The first value that defines time is the animation-duration; any subsequent time value is the animation-delay.
  • If there is a conflict between a keyword and the animation-name, the keyword value will take precedence if it appears first.
  • Any omitted values will fall back to their initial state, as with any CSS shorthand property.

Applying multiple animations to a single element

One final feature it’s good to be aware of is that you have the option to apply multiple animations to a single object by comma-separating the animations.

Here’s an example using the shorthand:

.box {
  animation: moveObject 2s ease-in-out, fadeBox 3s linear;

Here, I’ve defined two different animations that would map to two different sets of keyframes, but would apply to the same object. That same code could be written in longhand as:

.box {
  animation-name: moveObject, fadeBox;
  animation-duation: 2s, 3s;
  animation-timing-function: ease-in-out, linear;

Notice how each property includes two values separated by commas. In this instance, the shorthand would almost definitely be easier to read and maintain.

Wrapping up this CSS animations tutorial

If you’re a CSS beginner and this CSS animations tutorial was your first dip into experimenting with moving stuff on web pages, I hope the lesson was comprehensive enough. You might even be able to incorporate CSS variables with animations to make them even more powerful.

👉 One final warning: Use animation in moderation and remember that some web users might be negatively affected by blinking colors and other fast-moving objects.

With practice, the syntax and the concepts for building CSS animations will stick with you and you’ll definitely benefit from fiddling around with the code in the different demos.

Yay! 🎉 You made it to the end of the article!

Inline Feedbacks
View all comments

Or start the conversation in our Facebook group for WordPress professionals. Find answers, share tips, and get help from other WordPress experts. Join now (it’s free)!