CSS Animations for Beginners – (A Step by Step Guide)

✔︎ Last updated on September 29th, 2022

If you are looking for a complete beginner’s tutorial on CSS animation, this post is for you.

In this article, I cover all the basics of how you can animate HTML elements using CSS.

Along the way, you will create the following bouncing ball animation👇.

https://csswolf.com/wp-content/uploads/2022/09/bouncing-ball-animation-in-CSS.gif
We will create this animation in this post.

I strongly suggest you follow along with this guide in Codepen here.

The need for Animation

Every animal in the animal kingdom (humans included) is equipped to perceive motion subconsciously. In the wild, you can live for another day if you quickly distinguish the moving thing as either predator or prey.

This evolutionary trait is still present in humans even after we have left behind our hunter-gatherer lifestyle.

We can use this trait to make our web pages more intuitive and friendly to users.

For example, in the image below, the text box vibrates and jiggles sharply whenever a user fills in a wrong number.

Animation can make a webpage intuitive and user-friendly.

This snappy, intuitive animation shows the user that the entered number doesn’t belong to this network operator.

I hope you are sold on the importance of animation.

Why CSS Animation?

Simply because – performance and ease of use.

CSS animations are performant in comparison to animations done by JavaScript. Secondly, they are natively supported by all browsers.

And third, they are deceptively easy to implement. You can write code for a CSS animation in less than a minute without knowing anything single line of JavaScript.

Let’s see how.

Setting up the stage

In this bouncing ball animation, we have two animated elements –

  1. The bouncing ball, and
  2. the shadow that grows and shrinks in rhythm with the ball.

Therefore, in the code below, I have created a ball and a shadow. I have also centered them on the page using some basic CSS.

This will be my HTML code –

HTML
<div class="box">
    <div class="ball"></div>
    <div class="shadow"></div>
</div>

And this will be my CSS –

CSS
body {
    height: 400px;
    /* Centers the ball and the shadow on the page. */
    display: flex;
    justify-content: center;
    align-items: end;
}

.ball {
    /* Creates a ball of blue color */
    width: 100px;
    height: 100px;
    border-radius: 50%;
    background-color: #0052ff;
}

.shadow {
    /* 	creates a shadow */
    width: 100px;
    margin: auto;
    box-shadow: 0px 0px 15px 2px #111;
}

Here’s the output –

<div class="box">
	<div class="ball"></div>
	<div class="shadow"></div>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	box-shadow: 0px 0px 15px 2px #111;
}

Now let’s come to the basics of CSS animation.

Define Keyframes

The word keyframe is made up of two words – Key + Frame.

This term became popular in the animation industry in the early 20th century. In traditional animation, before the invention of computers, every frame of a sequence was drawn by hand.

It means that for a smooth-looking 24fps video, the artist had to draw (by hand!) 24 frames for every second of the video. Needless to say, it was a tedious and cumbersome task for the animators.

It is therefore that the animation studios like Disney would hire background artists who could quickly create the intermediate frames.

The lead animator would create two frames, one for the start and one for the end. The background artists would then create in-between frames.

For example, suppose a character is to be moved from Point A to Point B. The lead animator would draw these two frames (called keyframes).

CSS Animations — lead animators would define only first and last keyframe.

Then, the background artists would draw these in-between frames.

CSS Animations — secondary artists would draw the in-between frames.

The number of these in-between frames would be determined by the duration and framerate of the sequence.

The same concept is used in CSS animation except that here,

we are the lead animators, and the CSS engine (or web browser) is our background artist.

We will define two (or more) keyframes and the browser will draw the intermediate frames by itself using some mathematical calculations.

Now the question arises, how do we tell the browser what our keyframes are? CSS has a remarkably simple notation —

CSS
@keyframes animation-name {
    from { 
	/* current values */
    }

    to { 
	/* new values */
    }
}

Simply, we tell the browser to change the values of the element’s current properties to new values in a given duration. Note that from and to are CSS keywords. You can actually use them in your keyframe definitions.

We can also define keyframes in percentages, like this —

CSS
@keyframes animation-name {
    0% { 
	/* example */
	transform: translateY(-400px);
    }
	
    80% {
        transform: translateY(-200px);
    }

    100% { 
	transform: translateY(0);  
    }
}

In the above code, we are telling the browser that when the animation starts (0%), move the element up 400px in -y direction. Then, in the first 80% of the duration, move it down by 200px. And then, drop it to 0px in the remaining 20% duration.

The order of writing keyframes doesn’t matter. So this should also work –

CSS
@keyframes animation-name {
    100% { 
	width: 200px;
    }
    
    80% {
        width: 500px;
    }

    0% { 
	width: 200px;
    }    
}

Also, you can omit writing both frames (0% and 100%). The browser will automatically set properties’ values to their defaults (or to the values specified by you in your CSS stylesheet).

So, this code –

CSS
@keyframes animation-name { 
    50% {
        transform: translateY(-400px);
    }
}

is equivalent to this code –

CSS
@keyframes animation-name {
    0% {
        /* default value */
        transform: translateY(0px);
    }
    
    50% {
        transform: translateY(-400px);
    }

    100% {
        /* default value */
        transform: translateY(0px);
    }
}

Also, if two keyframes are the same, you can write them comma-separated. So, the above code is equivalent to —

CSS
@keyframes animation-name {
    0%, 100% {
        transform: translateY(0px);
    }
    
    50% {
        transform: translateY(-400px);
    }
}

Once we define our keyframes, we need to link them to an element. By linking them, the browser knows which element to apply the keyframes to.

We can do that by using the animation-name property.

Targeting elements using animation-name property

Once you have defined your keyframes, it is time to tie them up with a target element. This way, the browser knows which element to animate using those keyframes.

We use it like this –

CSS Animations for Beginners - (A Step by Step Guide)

Now that we have learned how to define keyframes and link them to a target element, let us proceed to write some actual code for our bouncing ball animation.

In the first frame, I will raise the ball to a height of 400px , and in the last frame, I will let it fall by 400px.

This will be our keyframe definition —

CSS
@keyframes bounce {
    0% {
        transform: translateY(-400px)
    }
    
    /* The following keyframe is written just for the sake of completeness. The animation works even if we omit it. */
    100% {
        transform: translateY(0px)
    }
}
<div class="box">
	<div class="ball"></div>
	<div class="shadow"></div>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;

	/* 	link the element with keyframes */
	animation-name: bounce;
}

@keyframes bounce {
	0% {
		transform: translateY(-400px);
	}
	100% {
		transform: translateY(0px);
	}
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	box-shadow: 0px 0px 15px 2px #111;
}

Oops! the animation doesn’t run! Why?

Because we haven’t specified a duration yet.

The default duration of CSS animations is 0, so we must set a duration other than zero for an animation to run.

Set a duration using the Animation-duration property:

Let’s set the animation-duration to 1 second.

We can do that like this –

CSS
.ball {
    /* write code so far here */

    animation-duration: 1s;
}
<div class="box">
	<div class="ball"></div>
	<div class="shadow"></div>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;

	/* 	link the element with keyframes */
	animation-name: bounce;

	animation-duration: 1s;
}

@keyframes bounce {
	0% {
		transform: translateY(-400px);
	}
	100% {
		transform: translateY(0px);
	}
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	box-shadow: 0px 0px 15px 2px #111;
}

Now it works. Perfect!

Also note that we can also set duration in decimals, like 1.3 seconds (1.3s) or in milliseconds (like 1300ms). Go ahead, try these in the Codepen.

Also, the animation-duration property doesn’t accept negative values (because negative duration doesn’t make sense).

This animation is nowhere close to our desired bouncing ball. It has several issues. Let’s fix them one by one.

First, it feels a little slow. The ball is taking too much time to hit the floor.

In my testing and tweaking, I have found that the duration of 0.65 seconds feels a bit more natural. So, let’s set the animation-duration to 0.65.

The second issue with this animation is that the animation stops after running only once. I want it to run forever. What to do?

animation-iteration-count

Well, we are in luck! We can use the animation-iteration-count property to define the number of times we want this animation to work.

We can set animation-iteration-count to any positive integer. We can even set it to infinite to run the animation indefinitely.

CSS
.ball {
    /* write code so far here */

    animation-iteration-count: infinite;
}
<div class="box">
	<div class="ball"></div>
	<div class="shadow"></div>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;

	/* 	link the element with keyframes */
	animation-name: bounce;

	animation-duration: 1s;

	animation-iteration-count: infinite;
}

@keyframes bounce {
	0% {
		transform: translateY(-400px);
	}
	100% {
		transform: translateY(0px);
	}
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	box-shadow: 0px 0px 15px 2px #111;
}

animation-direction

There’s another problem. This ball is only falling, it’s not bouncing back. Why?

Because in every iteration, the animation is only going forward (from 0% to 100%).

What we want is that it should first go in the normal direction i.e. from 0% to 100% and then it should go in reverse i.e. from 100% to 0%. In other words, we want it to alternate between the normal and reverse direction after every iteration.

We can do that by animation-direction property.

CSS
.ball {
    /* write code so far here */

    animation-direction: alternate;
}
<div class="box">
	<div class="ball"></div>
	<div class="shadow"></div>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;

	/* 	link the element with keyframes */
	animation-name: bounce;

	animation-duration: 1s;

	animation-iteration-count: infinite;

	animation-direction: alternate;
}

@keyframes bounce {
	0% {
		transform: translateY(-400px);
	}
	100% {
		transform: translateY(0px);
	}
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	box-shadow: 0px 0px 15px 2px #111;
}

To summarize, the property animation-direction can take four values —

normal – to move the animation from 0% to 100%

reverse – to move the animation from 100% to 0%

alternate – to alternate between forward and backward after every iteration.

alternate-reverse – animation will start from reverse direction and then alternate.

Go ahead and play with these values in the Codepen.

We are much close to our desired animation but there’s still a problem.

The bounce of the ball doesn’t feel natural.

That’s not how objects in the real-world fall. We need a way to incorporate the effects of gravity.

Enter animation-timing-function.

animation-timing-function

Using this property, we can define how the animation progresses. We can adjust the speed curve of animation throughout the duration.

In the physical world, when a ball falls, it starts slow. Its speed gradually increases because of gravity until it hits the ground. As the ball progresses downward, it increasingly covers more distance per unit of time.

We can tell the browser all this using the property animation-timing-function.

We set it like this –

CSS
.ball {
    /* write code so far here */

    animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.22);
}

Cubic-bezier

You might be wondering what this cubic-bezier is.

Cubic-bezier curve is a mathematical curve that has 4 points. It looks like this –

CSS Animations for Beginners - (A Step by Step Guide)

P0 is the first point which is set at (0,0) and P3 is the last point which is set at (1,1).

P1 and P2 are control points of the format (x,y). Here, x denotes the time and y denotes the progress of the animation.

Using the cubic-bezier function, we define our control points P1 and P2, in the format – (x1, y1, x2, y2).

The curve with values cubic-bezier(0.33, 0, 0.66, 0.22) looks like this –

CSS Animations for Beginners - (A Step by Step Guide)

As you can see in the graph above, the animation starts slow, and gradually, it picks up speed as it nears the end (similar to the speed of the falling ball).

Now that we have covered the theory, let’s plug in the values and see if it works.

<div class="box">
	<div class="ball"></div>
	<div class="shadow"></div>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;

	/* 	link the element with keyframes */
	animation-name: bounce;

	animation-duration: 0.65s;

	animation-iteration-count: infinite;

	animation-direction: alternate;

	animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.22);
}

@keyframes bounce {
	0% {
		transform: translateY(-400px);
	}
	100% {
		transform: translateY(0px);
	}
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	box-shadow: 0px 0px 15px 2px #111;
}

It does.

I want to highlight here that the cubic-bezier function is not intuitive so you will have to play around with the values to get the desired effect. I myself got these values only after tinkering with them for about 5 minutes.

You can use tools like www.cubic-bezier.com to get an idea.

Also, CSS ships with several commonly used values of the cubic-bezier function predefined in CSS.

linearcubic-bezier(0, 0, 1, 1) The animation will run linearly.

easecubic-bezier(0.25, 0.1, 0.25, 1) This is the default value in CSS.

ease-in(cubic-bezier (0.42, 0, 1, 1) – The animation will start slow but end fast.

ease-outcubic-bezier (0, 0, 0.58, 1) – The animation will start fast but end slow.

ease-in-outcubic-bezier(0.42, 0, 0.58, 1) – The animation will start and end slow but will be faster in the middle. (This is default in PowerPoint animations.)

The same animation with other easings looks like this (👇) —

<div class="box">
	<!-- 	<h3>Ease</h3> -->
	<div class="ball ease"></div>
	<div class="shadow"></div>
	<h2>ease</h2>
</div>
<div class="box">
	<div class="ball ease-in"></div>
	<div class="shadow"></div>
	<h2>ease-in</h2>
</div>
<div class="box">
	<div class="ball ease-out"></div>
	<div class="shadow"></div>
	<h2>ease-out</h2>
</div>
<div class="box">
	<div class="ball ease-in-out"></div>
	<div class="shadow"></div>
	<h2>ease-in-out</h2>
</div>
<div class="box">
	<div class="ball linear"></div>
	<div class="shadow"></div>
	<h2 style="margin-left: 30px">linear</h2>
</div>
<div class="box">
	<div class="ball ball-5"></div>
	<div class="shadow"></div>
	<h2 class="cubic-bezier">Cubic-bezier(0.33, 0, 0.66, 0)</h2>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;

	/* 	link the element with keyframes */
	animation-name: bounce;

	animation-duration: 0.65s;

	animation-iteration-count: infinite;

	animation-direction: alternate;

	animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.22);
}

@keyframes bounce {
	0% {
		transform: translateY(-400px);
	}
	100% {
		transform: translateY(0px);
	}
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	box-shadow: 0px 0px 15px 2px #111;
}

h2 {
	position: absolute;
}

/* Easings */

.ease {
	animation-timing-function: ease;
}
.ease-in {
	animation-timing-function: ease-in;
}

.ease-out {
	animation-timing-function: ease-out;
}

.ease-in-out {
	animation-timing-function: ease-in-out;
}

.linear {
	animation-timing-function: linear;
}

Now it’s time to animate the shadow.

Notice that the shadow grows and shrinks in tune with the fall and bounce of the ball.

Therefore, the value of properties like animation-duration, animation-timing-function, animation-iteration-count, and animation-direction should be the same as that of the ball so that these two are always in sync with each other (👇).

<div class="box">
	<div class="ball ease"></div>
	<div class="shadow"></div>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;

	/* 	link the element with keyframes */
	animation-name: bounce;
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	margin: auto;
	box-shadow: 0px 0px 15px 2px #111;

	animation-name: shrink-and-grow;
}

.ball,
.shadow {
	animation-duration: 0.65s;
	animation-iteration-count: infinite;
	animation-direction: alternate;
	animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.22);
}

@keyframes bounce {
	0% {
		transform: translateY(-400px);
	}
	100% {
		transform: translateY(0px);
	}
}

@keyframes shrink-and-grow {
	0% {
		width: 20px;
	}
}

Our animation is almost complete. But we have still not discussed all the animation properties CSS has to offer.

There are three remaining properties – animation-delay and animation-fill-mode and animation-play-state.

animation-delay

As you might have guessed, we can use this property to delay an animation.

Similar to animation-duration, it accepts time values either in seconds (1s) or in milliseconds (1000ms).

It is particularly useful when we have applied two or more animations used on a page and we want one to play after the other.

<div class="box">
	<div class="ball ease"></div>
	<div class="shadow"></div>
</div>

<div class="box">
	<div class="ball delayed"></div>
	<div class="shadow"></div>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;

	/* 	link the element with keyframes */
	animation-name: bounce;
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	margin: auto;
	box-shadow: 0px 0px 15px 2px #111;

	animation-name: shrink-and-grow;
}

.ball,
.shadow {
	animation-duration: 0.65s;
	animation-iteration-count: infinite;
	animation-direction: alternate;
	animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.22);
}

@keyframes bounce {
	0% {
		transform: translateY(-400px);
	}
	100% {
		transform: translateY(0px);
	}
}

@keyframes shrink-and-grow {
	0% {
		width: 20px;
	}
}

/* second ball wil be delayed */
.delayed {
	animation-delay: 0.35s;
}

Animation duration also accepts negative values. The negative values make the animation start earlier than usual.

animation-fill-mode

By default, the styles defined in keyframe definitions don’t apply to an element when the animation is not playing. We can use animation-fill-mode property to override this behavior.

We can define what styles remain applied to the target element when the animation ends. It accepts three values – forwards, backwards and both.

forwards – the styles are applied from the last keyframe played.

backwards – the styles are applied from the first keyframe played.

both – The animation will follow the rules for both forwards and backwards, extending the animation properties in both directions.

none – The animation will not apply any styles to the target when it’s not executing.

<div class="box">
	<div class="ball forwards"></div>
	<div class="shadow"></div>
	<h3>Forwards</h3>
</div>

<div class="box">
	<div class="ball backwards"></div>
	<div class="shadow"></div>
	<h3>Backwards</h3>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;

	/* 	link the element with keyframes */
	animation-name: bounce;
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	margin: auto;
	box-shadow: 0px 0px 15px 2px #111;

	animation-name: shrink-and-grow;
}

.ball,
.shadow {
	animation-duration: 0.65s;
	animation-iteration-count: 3;
	animation-direction: alternate;
	animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.22);
}

@keyframes bounce {
	0% {
		transform: translateY(-400px);
	}
	100% {
		transform: translateY(0px);
		background-color: red;
	}
}

@keyframes shrink-and-grow {
	0% {
		width: 20px;
	}
}

.forwards {
	animation-fill-mode: forwards;
}

.backwards {
	animation-fill-mode: backwards;
}

animation-play-state

We can use animation-play-state property to pause or play the animation.

This property accepts two values –

paused – to specify that the animation is paused

running – to specify that the animation is running. This is the default value.

animation-play-state property is particularly useful when we want to play or pause an animation via javascript. For example, we might want to keep an animation paused until the element scrolls into the view or until the user fires an event such as a button click.

We have almost covered all the CSS animation properties but we can improve our bouncing ball animation a little bit more.

keyframes revisited

In real life, when a ball strikes the ground, it stretches and squashes a little and then regains its shape as it bounces back.

We can implement that by decreasing the height (squash) and increasing the width (Stretch) of the ball just as it strikes the ground.

<div class="box">
	<div class="ball forwards"></div>
	<div class="shadow"></div>
</div>
body {
	height: 400px;

	/* 	Horizontally centers the ball and the shadow. */
	display: flex;
	justify-content: center;
	align-items: end;
}

.ball {
	/* 	Creates a ball of blue color */
	width: 100px;
	height: 100px;
	border-radius: 50%;
	background-color: #0052ff;

	/* 	link the element with keyframes */
	animation-name: bounce;
}

.shadow {
	/* 	creates a shadow */
	width: 100px;
	margin: auto;
	box-shadow: 0px 0px 15px 2px #111;

	animation-name: shrink-and-grow;
}

.ball,
.shadow {
	animation-duration: 0.65s;
	animation-iteration-count: infinite;
	animation-direction: alternate;
	animation-timing-function: cubic-bezier(0.33, 0, 0.66, 0.22);
}

@keyframes bounce {
	0% {
		transform: translateY(-400px);
	}

	/* 	dummy frame so that width/height change only when the ball strikes the ground and not before that. */
	90% {
		width: 100px;
		height: 100px;
	}

	100% {
		transform: translateY(0px);

		/* 		stretch and squash */
		width: 120px;
		height: 82px;
	}
}

@keyframes shrink-and-grow {
	0% {
		width: 20px;
	}
}

This looks good enough.

animation shorthand property

You might be wondering if it isn’t too much work writing all seven properties with their lengthy names.

You are right. It is.

That’s why CSS provides the animation shorthand property using which you can set all properties at once.

It is a shorthand for name | duration | easing-function | delay |
iteration-count | direction | fill-mode | play-state

The order of writing these properties doesn’t matter that much except that you should always write the animation-duration before the animation-delay value. You can read more about the animation shorthand property on MDN.

1 Secret Tip to Get Better at CSS Animations

There’s a tool called Animate | Keyframes.app. Using this tool, you can easily learn to animate any element in a visual manner.

When you open the app, you are presented with an element and a number of different animatable properties on the right side. On the bottom bar, you have the option to set CSS animation properties like duration, easings, timing-function, iteration-count and so on.

CSS Animations for Beginners - (A Step by Step Guide)

At the bottom, there is an option to Add Stop using which you can define keyframes. At every stop, you can set the values of properties and the browser will play the animation when you hit the green play button on the right bottom side.

You can also get its CSS code by clicking on the green Get CSS button on the top bar.

Since everything is laid out visually, I believe it is super useful for beginners who have just started learning CSS animations.

Conclusion

In this post, we learned how to animate an element in CSS.

First, we define keyframes either using the keywords from and to or by using percentages. Then we tie them to a target element using animation-name property so that the browser knows which element to animate. And then we set a duration using animation-duration.

Remember that the animation won’t run unless we specify a non-zero duration because the default duration in CSS is fixed at 0.

You can use other CSS animation properties to further fine-tune your animations, –

animation-iteration-count : to specify how many times you want an animation to run.

animation-direction: to specify if you want to run an animation normal (0 to 100%) or reverse (100% to 0) or alternate between the two.

animation-timing-function: to adjust the speed curve of the animation.

animation-delay: to specify the delay (in seconds or milliseconds) after which the animation should start.

animation-fill-mode: to specify which styles (first frame or last frame) remain applied to the target element after the animation has ended.

animation-play-state: to specify if an animation should pause or run.

In this post, we also learned about a visual CSS animation tool called Keyframes.app.

I have more step-by-step tutorials on CSS animations which you might find super helpful. Here are some of them —

  1. How to make a radar scanner animation in CSS.
  2. How to make a rotating loader animation in CSS.

I hope you enjoyed this guide. If you liked it, please drop a line below in the comments.

Leave a Comment