DEV Community

Cover image for CSS Funstuff: CSS Spinner
Roland Taylor
Roland Taylor

Posted on • Edited on

CSS Funstuff: CSS Spinner

Hey all!

Time for a yet another CSS Funstuff tutorial! This time, we'll be creating an animated spinner with pure HTML+CSS! I have to warn you though, this one is a little longer than usual.

After all, it comes with territory, working with CSS.

Let's get right to it!


1st! Setting Up The Basics:

First, as always, let's style the background and set up some defaults. I use the same style in every project in this series, as you probably know by now.

* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  background-color: rgb(35, 35, 35);
  display: flex;
  justify-content: center;
  align-items: center;
  height: 100vh;
}
Enter fullscreen mode Exit fullscreen mode

2nd: Building Our Spinner Object in HTML:

We'll need one div for the inside of the spinner, which ironically, is the container for everything else. What can I say? CSS - it's fascinating.

<div class="spinner">
</div>
Enter fullscreen mode Exit fullscreen mode

We'll set up the CSS later, but for now, let's go ahead and add the divs that will make up the rest of the spinner.

<div class="spinner">
   <div class="n-s">
   </div>
   <div class="w-e">
   </div>
   <div class="nw-se">
   </div>
   <div class="sw-ne">
   </div>
</div>
Enter fullscreen mode Exit fullscreen mode

You'll notice I've named the classes:

  • "n-s"
  • "w-e"
  • "nw-se"
  • "sw-ne"

These names are not chosen at random, and if you have your thinking cap on, you've probably figured out what their names stand for:

  • "north->south"
  • "west->east"
  • "northwest->southeast"
  • "southwest->northwest"

Essentially, these are "navigation points" for where we'll be placing the pseudo-elements that make up the rest of our spinner. From this point onward, we'll only be tackling CSS.

The CSS Funstuff!

First let's set up a CSS keyframe animation called spin. It's always good to keep in mind how things cascade in CSS. It will give our spinner rotation, as well as set the border of the .spinner class.

@keyframes spin {
  0% {
    border-color: rgba(255, 0, 0, .735);
    transform: rotate(0deg);
  }
  50% {
    border-color: rgba(255, 0, 0, .235);
  }
  100% {
    border-color: rgba(255, 0, 0, .735);
    transform: rotate(360deg);
  }
}
Enter fullscreen mode Exit fullscreen mode

Next, let's style the .spinner class.

.spinner {
  animation: spin 5s linear 0s infinite normal;
  border: 2px solid;
  border-radius: 50%;
  height: 50px;
  position: relative;
  width: 50px;
}
Enter fullscreen mode Exit fullscreen mode

We'll set up another animation next, this time called pulse:

@keyframes pulse {
  0% {
    opacity: .5;
    transform: scale(0);
  }
  50% {
    opacity: 1;
    transform: scale(1);
  }
  100% {
    opacity: .5;
    transform: scale(0);
  }
}
Enter fullscreen mode Exit fullscreen mode

Now you may be wondering, where will this one go? After all, we've already animated the .spinner class! Well, that's where the pseudo elements come into play:

.spinner::before,
.spinner::after {
  border-radius: 50%;
  content: '';
  inset: 0;
  position: absolute;
}

.spinner::after {
  animation: pulse 1s linear 0s infinite normal;
  border: 1px solid rgba(255, 0, 0, .35);
}

.spinner::before {
  animation: pulse .735s linear .235s infinite normal;
  border: 5px solid rgba(255, 0, 0, .135);
}
Enter fullscreen mode Exit fullscreen mode

Now, we'll position all the child divs as needed:


.spinner div {
  position: absolute;
  height: 100%;
  width: 100%;
  left: 50%;
  top: 0;
}
Enter fullscreen mode Exit fullscreen mode

This piece won't be visible, but it's essential.

At this point, you should have something that looks like this:

Following this, we're going to build the rest of the spinner animation. It's a bit of work, so be prepared for reading a lot of code!

Setting up the animation:

As before, we'll tackle the animation first:

@keyframes stretch {
  0% {
    opacity: 0;
    transform: scaleY(0);
  }
  50% {
    opacity: 1;
    transform: scaleY(1.5);
  }
  100% {
    opacity: 0;
    transform: scaleY(0);
  }
}
Enter fullscreen mode Exit fullscreen mode

All the moving parts:

Remember the four classes we added earlier, .n-s, .w-e, .sw-ne, and .nw-se? Well, the final step is for us to style them:

.spinner div::before,
.spinner div::after {
  animation: stretch 2s linear 0s infinite;
  animation-fill-mode: both;
  background-color: white;
  content: '';
  height: 15px;
  left: -2.5px;
  position: absolute;
  width: 5px;
  z-index: -1;
}

.spinner div:after {
  top: -50%;
}

.spinner div::before {
  bottom: -50%;
}

.spinner .nw-se,
.spinner .sw-ne,
.spinner .w-e {
  left: 0;
}

.spinner .w-e {
  top: calc(50% - 2.5px);
  transform: rotate(90deg);
}

.spinner .sw-ne {
  transform: rotate(45deg);
}

.spinner .nw-se {
  transform: rotate(-45deg);
}

.spinner .nw-se::before,
.spinner .nw-se::after,
.spinner .sw-ne::before,
.spinner .sw-ne:after {
  left: calc(50% - 2.5px);
  left: calc(50% - 2.5px);
}

.spinner .sw-ne:after {
  animation-delay: .125s;
}

.spinner .w-e:after {
  animation-delay: .25s;
}

.spinner .nw-se:after {
  animation-delay: .35s;
}

.spinner .n-s:before {
  animation-delay: .5s;
}

.spinner .sw-ne:before {
  animation-delay: .65s;
}

.spinner .w-e:before {
  animation-delay: .75s;
}

.spinner .nw-se:before {
  animation-delay: .85s;
}
Enter fullscreen mode Exit fullscreen mode

The Final Product:

When it's all said and done, this is what you should get:

That's all for now! But wait, there's more! Download the source code. I'll soon update the source with a couple fun tweaks, as I often do in this series, so be on the look out!

[Visit my Gumroad page] for(https://rolandixor.gumroad.com) more like this.

Top comments (0)