Pulse Loader in Pure CSS

Pulse Loader in Pure CSS

A week ago I published a post on how to make a spinner in pure CSS. This time, I'm going to make something slightly more complicated: A Pulse Loader.

The HTML

The HTML for this is rather straight forward. All we need is a container element with two child elements to act as the ripples.

<div class="loader">
  <div class="pulse pulse1"></div>
  <div class="pulse pulse2"></div>
</div>

We give the container element a class of .loader. Then we set the class .pulse on both of the child elements together with their individual class names, .pulse1 and .pulse2.

Having a shared class name for the child elements will make the CSS a bit easier since we only have to apply styles to one class. We can then control the individual pulse animations using the .pulse1 and .pulse2 class names.

And that's all the HTML we'll need.

The CSS

The CSS is going to be a bit more complicated this time.

The container

First, we need to set the container styles.

We're going to set the width and height of the container to equal values. This will be important later when we set the border-radius. If the width and height aren't equal, the pules would be ovals instead of circles.

.loader {
  /* Make sure it's a circle */
  width: 32px;
  height: 32px;
}

Now, set the border-radius to actually make it be a circle.

.loader {
  /* Make it be a circle */
  border-radius: 50%;
}

We also need to set the position of the container to relative. Our .pulse class will later get a position of absolute and having their container be relative will make sure they stay within its bounds.

.loader {
  /* Make sure the children will behave */
  position: relative;
}

The last thing for the container is to give it some space to breathe. You can change this to whatever values you like, but keep in mind that the ripples will grow to twice the width and height. If we don't give it enough space, the ripples could be cut off.

.loader {
  /* Give it some space */
  margin: 2rem auto;
}

The pulses

As you can tell from the HTML, we're going to have two pulses. The styles of the pulses will be the same. The only thing that differs is the animation-delay but we'll get to that later.

First, create a border for the pulse. You can choose whatever color or thickness you want.

.loader .pulse {
  /* The color and thickness of the pulse */
  border: 3px solid blue;
}

Next, we'll make the pulses have the same starting position. We can do this by setting position: absolute;. That'll make sure our pulses aren't stacked on top of each other.

.loader .pulse {
  /* Make sure the pulses don't interfere */
  position: absolute;
}

Earlier, we specified the width and height of the loading container. Now, we'll want the pulses to have that same width and height. To achieve that, we can simply set both rules to 100%.

.loader .pulse{
  /* Fill up the parent */
  width: 100%;
  height: 100%;
}

We also want the pulses to be round, like their parent. So, we can just set the border-radius to inherit its value from the parent.

.loader .pulse{
  /* Make it round */
  border-radius: inherit;
}

To give the animation a nicer effect, we'll also scale down the pulses slightly.

.loader .pulse{
  /* Scale down */
  transform: scale(0.5);
}

The last thing we'll do on the styles for the pulses is to set a transition for it's opacity. We do this because when the animation starts over we don't want the pulse to immediately appear. We want it to look smooth.

.loader .pulse{
  /* Make it smooth */
  transition: opacity 200ms linear;
}

That is all the actual styling we need.

The animation

Now, it's time to create the animation to make it look like it's pulsing.

Remember that we added individual class names to the pulses? We'll use those now!

The first pulse, .pulse1, should start immediately and repeat infinitely. Meanwhile, the second pulse, .pulse2, should start after a slight delay. This is done by specifying two numeric values to the animation property.

First pulse:

.loader .pulse1{
  animation: pulse 1s infinite;
}

Second pulse:

.loader .pulse2{
  animation: pulse 1s 500ms linear infinite;
}

Notice that we also set the linear timing function on the second pulse. The first pulse, however, uses the default timing function, ease, which means it will be faster towards the middle of the animation and slow down at the beginning and end. We do this to get a more interesting effect.

Now, the animation itself.

@keyframes pulse{
  to{
    transform: scale(2);
    opacity: 0;
  }
}

The animation is simple. We set a to value, which determines the state at the end of the animation, to be completely transparent and grow to twice its original size.

This will make it seem like the pulses disappear out into the void and new ones appear to grow from the middle.

And we're all done. We should now have a repeating pulse effect.

Putting it all together

Let's put everything together.

The HTML:

<div class="loader">
  <div class="pulse pulse1"></div>
  <div class="pulse pulse2"></div>
</div>

The CSS:

.loader{
  /* Make sure it's a circle */
  width: 32px;
  height: 32px;

  /* Make it be a circle */
  border-radius: 50%;

  /* Make sure the children will behave */
  position: relative;

  /* Give it some space */
  margin: 2rem auto;
}
.loader .pulse{
  /* The color and thickness of the pulse */
  border: 3px solid blue;

  /* Make sure the pulses don't interfere */
  position: absolute;

  /* Fill up the parent */
  width: 100%;
  height: 100%;

  /* Make it round */
  border-radius: inherit;

  /* Scale down */
  transform: scale(0.5);

  /* Make it smooth */
  transition: opacity 200ms linear;
}
.loader .pulse1{
  animation: pulse 1s infinite;
}
.loader .pulse2{
  animation: pulse 1s 500ms linear infinite;
}

@keyframes pulse{
  to{
    transform: scale(2);
    opacity: 0;
  }
}

Conclusion

Even though this pulse effect is slightly more complicated than the spinner we did last week, it is still fairly simple to create.

You can, of course, customize this effect in a number of ways. You could change the colors of the pulses or even use different colors for each of them. You could change the animation timing functions to get interesting variations. Or you could simply add more pulses.

Next week, I'll create a skeleton loader. If you don't want to miss that, consider subscribing to my newsletter here on Hashnode. You could also follow me on Twitter(@chj_web).