Dead Simple Pure CSS Loading Spinner

Pretty much every piece of software out there has to process something - and if it's not instantaneous, the user probably needs to know that it's at least working on it, right? Right. That's where loading spinners come in—and today, I've got one for you that uses only one div and one CSS class (along with a pseudo-element). It's the most code-minimal I've seen, and uses not a single image in the whole thing. Ready?

I'll start by giving you the markup. Again, it's just one div with a class—if you can't handle that, then maybe you should be doing something else with your spare time (may I suggest eating glue?).

html
<div class="spinner"></div>

See the Pen KpKwMe by Jesse Couch (@designcouch) on CodePen.

Again, this will be a short post, as there's not a whole lot to explain here; here's the CSS.

.spinner {
height:60px;
width:60px;
margin:0 auto;
position:relative;
-webkit-animation: rotation .6s infinite linear;
-moz-animation: rotation .6s infinite linear;
-o-animation: rotation .6s infinite linear;
animation: rotation .6s infinite linear;
border:6px solid rgba(0,174,239,.15);
border-radius:100%;
}

.spinner:before {
content:"";
display:block;
position:absolute;
left:-6px;
top:-6px;
height:100%;
width:100%;
border-top:6px solid rgba(0,174,239,.8);
border-left:6px solid transparent;
border-bottom:6px solid transparent;
border-right:6px solid transparent;
border-radius:100%;
}

@-webkit-keyframes rotation {
from {-webkit-transform: rotate(0deg);}
to {-webkit-transform: rotate(359deg);}
}
@-moz-keyframes rotation {
from {-moz-transform: rotate(0deg);}
to {-moz-transform: rotate(359deg);}
}
@-o-keyframes rotation {
from {-o-transform: rotate(0deg);}
to {-o-transform: rotate(359deg);}
}
@keyframes rotation {
from {transform: rotate(0deg);}
to {transform: rotate(359deg);}
}

See updated code below.

Ok, now that we've got that down, let's go over what we're doing. First off, we're creating the basic spinner container by styling the div .spinner. We give it a light colored border and a border-radius so we're dealing with a circle instead of a box.

The pseudo-element (:before) is essentially creating an identically sized element, but instead of having a visible border all the way around, it only has a visible top border—this creates the part that actually visibly spins (the parent div's border is simply providing the "track" that the spinner rotates on).

After those two elements are done, all we have to do is animate the sucker, and that is done using CSS3 keyframe animation. You can name your animation whatever you like, but for the sake of semantics, ours is named "rotation". All we have to do is reference that in the style of the .spinner div, and we're done!

To adjust the speed or size of the spinner, simple use the .spinner class—no need to touch anything else.

Like what you've seen here, or have any questions at all? Give me a shout in the comments below.

Here's your demo, compadre.

demo

See the Pen KpKwMe by Jesse Couch (@designcouch) on CodePen.

** Updated **

As you may have noticed in the comments below, there is an even simpler way to pull this off. We can eliminate the pseudo element entirely since the border can be defined as 4 separate areas (top, left, bottom and right). Here's the updated CSS.

css
.spinner {
  height: 60px;
  width: 60px;
  margin: 94px auto 0 auto;
  position: relative;
  -webkit-animation: rotation .6s infinite linear;
  -moz-animation: rotation .6s infinite linear;
  -o-animation: rotation .6s infinite linear;
  animation: rotation .6s infinite linear;
  border-left: 6px solid rgba(0, 174, 239, .15);
  border-right: 6px solid rgba(0, 174, 239, .15);
  border-bottom: 6px solid rgba(0, 174, 239, .15);
  border-top: 6px solid rgba(0, 174, 239, .8);
  border-radius: 100%;
}

@-webkit-keyframes rotation {
  from {
    -webkit-transform: rotate(0deg);
  }
  to {
    -webkit-transform: rotate(359deg);
  }
}

@-moz-keyframes rotation {
  from {
    -moz-transform: rotate(0deg);
  }
  to {
    -moz-transform: rotate(359deg);
  }
}

@-o-keyframes rotation {
  from {
    -o-transform: rotate(0deg);
  }
  to {
    -o-transform: rotate(359deg);
  }
}

@keyframes rotation {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(359deg);
  }
}

See the Pen KpKwMe by Jesse Couch (@designcouch) on CodePen.

Did I help you out?

Read More

←  Accepting Design Critique Styling Form Radio Buttons  →

There are 44 comments. Add Yours.

A Note from the Moderator

Thanks for taking the time to comment! I'll respond as quickly as possible if necessary. In the meantime, please keep the following in mind:

  • All comments must be appropriate. I'll delete 'em if you get nasty.
  • Please allow for response time. I'm here as much as possible, but can't always respond as quickly as some would like.
  • Please stay on topic.
  • I don't work for free—if you want custom work, feel free to get in touch and I'll write up a quote!
  1. Jonathan Kapaldo

    Jonathan Kapaldo

    Jun 24, 2013

    Thanks for the tutorial. I don't use css animation often, so this answered my questions and need for a loading spinner. Thanks!

    Reply to Jonathan

    1. Jesse

      Jesse

      Jun 24, 2013

      Definitely appreciate the feedback! In my opinion, once the browser adoption catches up, CSS animation will replace a lot of the jquery animations you see nowadays. Getting an understanding of how to use them now helps to future-proof ourselves as developers. Glad my resource was able to help you out.

  2. JP DeVries

    JP DeVries

    Jun 26, 2013

    Very cool. Going to have to use this on my next project. If needed, I think you could detect .no-cssanimations will modernizr.js and fallback to something like a GIF

    Reply to JP

    1. Jesse

      Jesse

      Jun 26, 2013

      Glad to help. Just had a moment of clarity, and realized that the pseudo-element can probably be eliminated too; just style each border area of .spinner (top, bottom, left, right) separately and make one the darker color. This eliminates the pseudo element entirely and then you're left with one div and one class. Period. I've updated the demo code to reflect this.

  3. Surce Beats

    Surce Beats

    Jul 09, 2013

    Guapamente pero... Compadre? jajaja

    Reply to Surce

    1. Jesse

      Jesse

      Jul 09, 2013

      Perdone mi español, Surce. ¡No es muy bueno! Acaba de tardarme 5 minutos para escribir esta respuesta.

  4. Dave

    Dave

    Jul 17, 2013

    Very cool. I will definitely use this in current and future projects. Thanks for sharing!

    Reply to Dave

    1. Jesse

      Jesse

      Jul 31, 2013

      Thanks Dave - glad I could be of help!

  5. Marek

    Marek

    Jul 31, 2013

    This is very nice, thank you! (And yes, the :before is not needed)

    Reply to Marek

    1. Jesse

      Jesse

      Jul 31, 2013

      Thanks, Marek! I had a lot of fun figuring this one out.

  6. Matias Larsson

    Matias Larsson

    Aug 21, 2013

    Nice! But I think the css is missing a final closing curly bracket, right?

    Reply to Matias

    1. Jesse

      Jesse

      Aug 28, 2013

      Good catch, Matias-yes, it should have a final closing bracket.

  7. Allen

    Allen

    Sep 11, 2013

    Really nice to find a load spinner with such lean markup. Saved me on a project where I could edit the css but was miles out of my depth on the js, so couldn't really change the html it generated.

    It looks like the code above hasn't been edited to remove the .before pseudoclass, btw. But it was as simple to change as you suggest in your comment.

    Reply to Allen

  8. Ben Sky

    Ben Sky

    Sep 21, 2013

    One word for this, mega. Thanks Jesse.

    Reply to Ben

    1. Jesse

      Jesse

      Sep 21, 2013

      Thanks Ben - I do what I can!

  9. Maarten Wolzak

    Maarten Wolzak

    Oct 07, 2013

    Thanks for this beautiful solution. Lots of tuts out there with multiple div's. This is a very nice, clear option.

    Reply to Maarten

    1. Jesse

      Jesse

      Oct 07, 2013

      My pleasure, Maarten. Glad I could be of assistance!

  10. Ryan Charmley

    Ryan Charmley

    Oct 08, 2013

    Hey, great work Jesse! If you're using Twitter Bootstrap 3, these directives will fix the CSS issue when added to the .spinner:before class.

    -webkit-box-sizing: content-box;
    -moz-box-sizing: content-box;
    box-sizing: content-box;

    Reply to Ryan

    1. Jesse

      Jesse

      Oct 14, 2013

      Yup - typically try to use box-sizing in my initial CSS reset (along with margin:0 and padding:0 and the like). Thanks for the feedback!

  11. Chris

    Chris

    Oct 16, 2013

    There's a closing } missing in the very last line! Beside that, EXCELLENT, man!

    Reply to Chris

    1. Jesse

      Jesse

      Oct 18, 2013

      Thanks, Chris! I've updated the article not only with that bracket, but with an even simpler way of doing this (we can eliminate the pseudo element and just use the .spinner class by itself).

  12. Larry King

    Larry King

    Nov 05, 2013

    Jesse, Thanks very much. I am having one issue:
    on my iPhone4 using Chrome browser, my web page is super sluggish in sliding up and down. However, using Safari on the same phone the web page is very responsive. I am just setting the style to display:none; of the div, but even pausing the animation does not help. Any suggestions?
    Thanks - Larry

    Reply to Larry

    1. Jesse

      Jesse

      Nov 06, 2013

      If you're using this code on your webpage, I can almost guarantee that it's something else on the page. There is VERY little going on here that could slow down a browser. CSS animations don't enjoy complete support in all browsers (although Chrome handles it really well in almost all cases) but even in browsers that don't support them, the overhead from a rendering standpoint is next to nothing. If you wanted to share the page in question, I could look more closely at the code and possibly be a bit more help.

    2. Larry King

      Larry King

      Nov 07, 2013

      Hey Jesse. Thanks for responding. I assume that I have something else going on, but I wanted a quick check. I have some deadlines that I am up against this week and next, so I will get back to you afterwards when I have some more time. I like your solution and I want to use it. Until then ...
      Larry

    3. Larry King

      Larry King

      Apr 14, 2014

      Jesse, this is Larry, from way back last Nov where I was having some troubles. Sorry it has taken me so long to get back, but all is working well now. I was using Google Sites at the time and have since completely abandoned that path. I am now on a much more mainstream web dev engine and life is good with your spinner. So thanks and regards.
      Larry

  13. Alex

    Alex

    Nov 19, 2013

    Awesome! I really like this!

    (I think you can rip out `position:relative;` in the updated example)

    Reply to Alex

    1. Jesse

      Jesse

      Nov 20, 2013

      As a general rule, I dislike static positioning; I usually give most things relative positioning out of habit, but technically you're correct, it could be eliminated here. Thanks, Alex!

  14. Samuel Rossille

    Samuel Rossille

    Nov 20, 2013

    Great job! I used your spinned for a personnal project. I'll share a link to the page soon. Thank you for sharing.

    Reply to Samuel

  15. Siva

    Siva

    Dec 12, 2013

    Hi,

    This is really awesome. Thanks for sharing.

    I have one issue in Firefox 25.x. The spinner stops rotating after ajax call complete and while rendering html (lot of dom nodes added dynamically using Knockout).

    Don't have any issues with Chrome or IE 11.

    Any ideas?

    Thanks,

    Reply to Siva

    1. Jesse

      Jesse

      Jan 18, 2014

      Siva,

      I can't say that I am entirely certain there. Chances are you've run into a Firefox bug where it is for some reason pausing all page actions. If I were you, I'd peruse the Bugzilla site (Mozilla's Firefox bug reporting platform) and see if anyone has had any issues similar to yours. If not, report that bug so that Mozilla can squash it in the next release!

      https://bugzilla.mozilla.org/

  16. harald

    harald

    Jan 25, 2014

    Wow, that spinner really looks amazing. Would like to use it in some javascript library i am currently developing, but what license applies to your stuff ... ?

    Reply to harald

    1. Jesse Couch

      Jesse Couch

      Jan 25, 2014

      It's free to use in any way you like! Glad you like it.

    2. harald

      harald

      Jan 25, 2014

      Great! Thanks very much! :-)

    3. Jesse

      Jesse

      Jan 26, 2014

      My pleasure - be sure to share once you're done! I'm always on the lookout for a good js library.

  17. shi

    shi

    Mar 24, 2014

    Probably an animation bug in browser than your code but it's a curious case -

    (in Chrome Version 33.0.1750.152, Xubuntu) When the spinner is looked at on the page, cpu usage barely registers but if you scroll away on the same page whilst the spinner is still spinning away in the background, cpu usage hits almost a constant 50%.

    And if you go on a different tab whilst all of this is happening, cpu usage goes back to barely registering. Go back to the same page with the spinner spinning away in the background so you're not look at it, cpu usage hits the constant 50%.

    I'm assuming the spinner is spinning tonnes faster when it's not being looked at if you've scrolled away on the same page. Of course, since this is just an interstitial, it probably doesn't matter but like I said, curious.

    By the way, thanks for this :}

    Reply to shi

  18. MAYO

    MAYO

    Mar 25, 2014

    Bravo.

    Reply to MAYO

  19. Luke Ruth

    Luke Ruth

    Apr 23, 2014

    You could shorten up the border declarations by doing something like:

    border: 6px solid rgba(0,174,239,.15);
    border-top-color: rgba(0,174,239,.8);

    Not a big deal or anything but I think it actually makes the code a little more readable. Great job! Really slick solution.

    Reply to Luke

  20. Dave

    Dave

    Aug 08, 2014

    Thanks! Font-relative sizing and layout options...

    http://codepen.io/anon/pen/EqdhG

    Reply to Dave

  21. samuel

    samuel

    Aug 27, 2014

    thank you so much for the code !! i put a normal picture and removed the borders and there i go, like a GIF animated image.
    Thanls A Lot Jesse :)

    Reply to samuel

    1. Jesse

      Jesse

      Aug 28, 2014

      That works, too! Glad to help.

  22. Andrew Robbins

    Andrew Robbins

    Nov 10, 2014

    Thanks for the awesome work Jesse. Just what I needed.

    Reply to Andrew

  23. Rowan

    Rowan

    Dec 25, 2014

    Very nice - I added a little modification to display it responsive on mobile devices with simple media queries:

    @media (max-width: 767px) {
    .spinner {
    height:30px;
    width:30px;
    }
    }

    @media (max-width: 979px) {
    .spinner {
    height:40px;
    width:40px;
    }
    }

    @media (min-width: 980px) {
    .spinner {
    height:60px;
    width:60px;
    }
    }

    Regards

    Rowan

    Reply to Rowan

  24. Rowan

    Rowan

    Dec 25, 2014

    Very nice - I added a little modification to display it responsive on mobile devices with simple media queries:

    @media (max-width: 767px) {
    .spinner {
    height:30px;
    width:30px;
    }
    }

    @media (max-width: 979px) {
    .spinner {
    height:40px;
    width:40px;
    }
    }

    @media (min-width: 980px) {
    .spinner {
    height:60px;
    width:60px;
    }
    }

    Regards

    Rowan

    Reply to Rowan

  25. Ed

    Ed

    Dec 15, 2015

    FYI spinner is perfect in firefox.
    Vibrating in Chrome.
    You might want to check it out.

    Reply to Ed