How to create a CSS-only loader with one element

Temani Afif

Written by Web Developer

August 7, 2022
How to create a CSS-only loader with one element

A loader is an important component of a website. It can be used in many places where we need to show that something is in progress. Such a component needs to be as simple as possible and in this post, we will learn how to create different CSS-only loaders with an optimized code.

I have created a collection of more than 500 CSS-only loaders. They are made using only one element and we are going to dissect the code of some of them.

The Classic CSS Loaders


Let’s start with some classic loaders where we will animate the “Loading…” text in different ways.

Let’s start with the fourth and fifth loaders where I am relying on a clip-path animation.

.classic-4 {
  font-family: monospace;
  clip-path: inset(0 3ch 0 0);
  animation: c4 1s steps(4) infinite;
}
@keyframes c4 {
  to {clip-path: inset(0 -1ch 0 0)}
}

The main trick relies on using a Monospace font to make sure all the characters have the same width defined by 1ch then we use clip-path to show/hide some of the characters. For the fourth loader I simply consider the 3 dots at the end and here is a figure to illustrate the trick:

illustration of the clip-path:inset

Initially, we hide all the dots by using inset(0 3ch 0 0). This means we are hiding a width equal to 3ch from the right side (only three characters). Then we animate this to inset(0 -1ch 0 0).

Intuitively we should use inset(0 0 0 0) to show all the dots and this is true if we want to create a continuous animation like the below:

But we want a discrete animation using steps() and for this, we need to go beyond the element boundary by an extra character.

We are doing the same with the fifth loader but instead of hiding only the 3 dots using inset(0 3ch 0 0) we are hiding all the text using inset(0 100% 0 0). Same logic, two different loaders!

Let’s now check the seventh and eighth loaders. For those, I am relying on gradient animation. Here is a step-by-step illustration to understand the trick:

We first start by creating and animating a gradient. The trick is to have a gradient with two colors that has a width twice bigger than the main element then we slide that gradient from right to left to swap between both colors.

.one {
  background:
     linear-gradient(90deg,red calc(50% + 0.5ch),#000 0) 
     right/calc(200% + 1ch) 100%;
  animation: c1 2s infinite linear;
}
@keyframes c1 {to{background-position: left}}

Like the previous loaders, we add an extra 1ch which is needed later for the discrete animation.

Then we use that gradient to color the text instead of the background and we update the linear animation to a discrete one using steps. As simple as that!

And by simply using a different gradient we create another loader where we color each letter instead of coloring all the text.

background:
  linear-gradient(90deg,#000 calc(50% - 0.5ch),red 0 calc(50% + 0.5ch),#000 0) 
   right/calc(200% + 1ch) 100%

I am also using a text-shadow trick for some loaders where the idea is to duplicate the “loading…” text using a shadow and then animate it.

For example with the ninth loader from the above collection

.classic-9 {
  font-weight: bold;
  font-family: monospace;
  font-size: 30px;
  color:#0000;
  overflow:hidden;
  animation:c9 5s infinite cubic-bezier(0.3,1,0,1);
}
@keyframes c9 {
  0%  {text-shadow: 0    0 #000, 11ch 0 green, 22ch 0 red, 33ch 0 blue,44ch 0 #000}
  25% {text-shadow:-11ch 0 #000,  0ch 0 green, 11ch 0 red, 22ch 0 blue,33ch 0 #000}
  50% {text-shadow:-22ch 0 #000,-11ch 0 green,  0ch 0 red, 11ch 0 blue,22ch 0 #000}
  75% {text-shadow:-33ch 0 #000,-22ch 0 green,-11ch 0 red,  0ch 0 blue,11ch 0 #000}
  100%{text-shadow:-44ch 0 #000,-33ch 0 green,-22ch 0 red,-11ch 0 blue, 0ch 0 #000}
}

I have five shadow layers and each time I update the X offset to create a sliding animation. Here is what we get if we omit the overflow property:

By making the first and last layer identical (with the same color) we get a continuous animation and if we hide the overflow, the illusion is perfect!

The Flipping Square CSS Loaders


Let’s try another type of loader.

This time, we are going to consider rotation and perspective to create the 3D illusion of a flipping square. If we check the code of the first loader we can see:

.flipping-1 {
  width: 40px;
  aspect-ratio: 1;
  background: #000;
  animation: f1 1s infinite;
}

@keyframes f1 {
  0%   {transform: perspective(150px) rotateX(  0deg)}
  100% {transform: perspective(150px) rotateX(180deg)}
}

Note the use of perspective which is the key here to creating the flipping animation. Without it, we get the following:

It’s clear that the first one is not cool.

All the remaining loaders use the same trick by adding more animation to get a different variation each time. For the second one, we are updating the background color at half the road to simulate an element with two different faces.

.flipping-2 {
  width: 40px;
  aspect-ratio: 1;
  animation: 
    f2-1 2s infinite linear,
    f2-2 1s infinite steps(1) alternate;
}

@keyframes f2-1 {
  0%   {transform: perspective(150px) rotateX(  0deg)}
  100% {transform: perspective(150px) rotateX(360deg)}
}

@keyframes f2-2 {
  0%  {background:#ffa516}
  50% {background:#f03355}
}

The second animation (the one that changes the background) is discrete (it uses steps(1) ) with a duration equal to half the duration of the rotation animation. With this configuration, the color will change at the 90deg when the element is visually invisible to us. This will make the illusion perfect: our brain will consider it as a two faces element while in reality, it’s only one face that changes its color instantly at 90deg

for the third loader, I am considering two rotations:

.flipping-3 {
  width: 40px;
  aspect-ratio: 1;
  animation: 
    f3-1 2s infinite linear,
    f3-2 3s infinite steps(1) -.5s;
}

@keyframes f3-1 {
  0%   {transform: perspective(150px) rotateX(  0deg) rotateY(0deg)}
  50%  {transform: perspective(150px) rotateX(180deg) rotateY(0deg)}
  100% {transform: perspective(150px) rotateX(180deg) rotateY(180deg)}
}

@keyframes f3-2 {
  0%  {background: #ffa516}
  33% {background: #f03355}
  66% {background: #25b09b}
}

I do the first rotation on the X axis and another one on the Y axis. For the coloration, we have now 3 colors but the logic is still the same. I do an instant change of color at the 90deg angles to create the illusion of flipping sides.

Here is a demo to better see the trick:

If you check the code of the remaining loaders, you will see that the main trick is the same. Each time I make the animations more complex to add more steps to the full animation but I am always relying on the rotation combined with perspective and the color change illusion.

More CSS Loaders


In this article, we covered a few CSS tricks that allow us to create around 20 different single-element CSS loaders but we can do more. I have a collection of more than 500 loaders and I wrote other articles where I detail the CSS tricks I have used. They can be a good follow-up to this one:

Temani Afif
About the Author
Temani Afif

Temani Afif is an expert web developer, a content creator, and a CSS addict. He is the mastermind behind css-challenges.com, css-generators.com, css-only.art, css-articles.com, and a lot of CSS stuff. He's also an active contributor at Stack Overflow answering all kinds of CSS questions.

View all posts by Temani Afif
Discount

Enter Discount Code MOVEME During The SIGN UP Process To Get 90% Off Your First Month

with the discount code

MOVEME

Use Code Now
Jivo Live Chat