✔︎ Last updated on September 29th, 2022
If you are wondering how to make a pure CSS loading animation, then you have come to the right place.
In this article, I will explain step by step how you can create the following loading animation with pure CSS (without touching a single line of JavaScript).
At the end of this article, you will also find the complete code in a Codepen block with which you can play around and experiment.
I have also written an ultimate beginner’s guide to CSS Animation. If you are new to CSS animation, I strongly suggest you check it out before reading this article.
Now, let’s begin with today’s tutorial.
Setting up the scene
I have only one element (pink square) which will rotate so here’s my entire HTML code for this project –
<div class="loader"></div>
Let’s come to the CSS part.
I have applied the following styles on the body
element –
- I like to place elements in the center of the page so I will set
display: grid
andplace-items: center
. - Furthermore, as I want to vertically center the loader on the page, I will have to set a height of 100vh. If you don’t set a height, the loader will touch the upper border of the page.
Our code looks like this –
body {
/* center the child elements on the page */
display: grid;
place-items: center;
height: 100vh;
}
Now, it’s time to design our rotating loader.
I am applying some basic styling to it. Since it is a square, I have set equal height
and width
of 150px
. I have also set the background-color
to #ff0077
.
Here’s our code –
.loader {
/* set appearance of the square */
width: 150px;
height: 150px;
background-color: #ff0077;
}
Our output so far looks like this –
Now it’s time to animate this.
Animating the loader
I will use the animation
shorthand property to set animation parameters on this loader.
Specifically,
- I have to name the animation, I will call it
load
. - I have to set a duration, I will set it at
4s
(4 seconds). The defaultanimation-duration
in CSS is 0 so you must set a non-zero duration for an animation to run. - The loading animations don’t run a definite number of times. They are essentially designed to run until the user’s wait is over, so we will set them to run for
infinite
times.
We can set all these things using the following line of code –
.loader {
/* write code so far here */
/* set animation properties */
animation: load 4s infinite;
}
Now, all there remains to be done is to define our keyframes.
As we can see in the featured image above, our animation is executed in 4 steps. At every step, the box rotates by 90 degrees.
So we can define 4 keyframes at 25%, 50%, 75%, and 100%. At each keyframe, we will rotate
the box along the Z
-axis by 90 degrees more than the previous keyframe. So, at 25%, the rotation will be 90 degrees; at 50%, it will be of 180 degrees, and so on.
Now the question arises, why along the z-axis?
Because the square is rotating around an imaginary pivot point on the computer screen. An imaginary line perpendicular to the computer screen passing through the pivot point will be the z-axis. So we will use rotateZ()
function.
This is our code –
/* define keyframes */
@keyframes load {
25% {
transform: rotateZ(90deg);
}
50% {
transform: rotateZ(180deg);
}
75% {
transform: rotateZ(270deg);
}
100% {
transform: rotateZ(1turn);
}
}
This is our output –
Uh-Oh! The box is rotating around its center. That’s not what we want.
We want it to rotate around its top-left corner. Fortunately, we have a property that lets us change its center of rotation – transform-origin
property.
By default, the rotational axis of objects in CSS passes through their center. We have to transform that rotational axis from the center to the top left corner; transform-origin
property lets us do exactly that.
We can use it like this –
.loader {
/* write code so far here /*
/* any of the following works */
transform-origin: left top; //either this
transform-origin: 0 0; // or this.
}
This is our output –
Much better!
There’s one more thing that I want to change here – timing-function
.
By default, the ease
timing is set on animations in CSS. But I do not want that here.
I want the animation to be snappy. I want it to look like the square is tied with a rubber band. The square tries to rotate but the rubber band keeps pulling. And then, suddenly, the band snaps due to stretching, and the square slams into place.
In my trials and errors on www.cubic-bezier.com, I found the values cubic-bezier(1,-0.01,.89,0)
make the animation feel elastic.
We can put these values in the animation
shorthand property itself, like this –
.loader {
/* write code so far here */
/* set animation properties and timing function */
animation: load 4s infinite cubic-bezier(1, -0.01, .89, 0);
}
And this is our final output –
<div class="loader"></div>
body { /* center the child elements on the page */ display: grid; place-items: center; height: 100vh; } .loader { /* set appearance of the square */ width: 150px; height: 150px; background-color: #ff0077; /* set animation properties */ animation: load 4s infinite cubic-bezier(1,-0.01,.89,0); transform-origin: left top; } /* define keyframes */ @keyframes load { 25% { transform: rotatez(90deg); } 50% { transform: rotateZ(180deg); } 75% { transform: rotateZ(270deg); } 100% { transform: rotateZ(1turn); } }
I can think of one more way of improving this. We can play a pop sound whenever it completes a 90-degree turn, to give it an even more realistic effect but it will require some JavaScript code to play.
That brings us to the end of our tutorial.
I hope you liked this article. I would love to know if you have a different approach to the same problem.
Please drop a line below if you have any queries.