Cleanest CSS spinner, ever

For some reason, I seem to have a fascination with CSS loaders these days. After recreating the Google loader with clean CSS recently, I set off to recreate the classic spinner with CSS. Yes, I know this has been done zillions of times, but I wanted a clean, maintainable, reusable solution, not just a proof of concept. Something with not tons of CSS and/or HTML elements.

I managed to recreate it with only 2 elements. I’m still not completely satisfied, as I was hoping to come up with a solution with just one element, but it’s still much better than all those solutions out there that use tons of elements and code.

So, how did I do it?

  • I use the ::before and ::after pseudoelements of the parent and child div to create the 4 first bars
  • I use box-shadow with no blur on all four of the above to create the remaining 4 bars
  • I rotate the whole element with a steps(8) timing function to create the animation

As with the Google-style loader, just changing the font-size on this scales the whole element, as everything is sized with ems. Also, there is fallback text, to make it accessible to screen readers. Tested in Chrome, Firefox, Safari, IE10. Should degrade gracefully on IE9 (spinner should look fine, just no animation).

Using a preprocessor for variables and calculations should simplify the code even further.

Enjoy 🙂

Ideas for further improvement are welcome. Remember that it’s not just the size of the code that matters, but also its simplicity.

  • This is fantastic! Nice work 😀

  • Neat!

  • Lukyvj

    Well done ! You nailed it !

  • gp

    “For some reason, I seem to have a fascination with CSS loaders these days”
    My broher, who is therapist, says that it is maybe because you want to have a baby….

    • I can’t help but wonder if I would have gotten this comment if I were male.

      • Alexander Sadler

        Haha don’t turn this into a gender debate

        • If you read a couple of comments on any kind of article written by a woman you will see that “people on the internet” obviously have a hard time disregarding gender. @365a706d629863f81da1d9ae2e64f32b:disqus is the one at fault here, not Lea.

        • JoaoBeno

          Lol, i see this same way as if i posted and someone stated “My brother, who is therapist, says that it is maybe because you should go out and have sex”…

          These jokes will aways exist on the web, man or woman, everybody need to learn how to deal with it… With male devs, they shot about their weirdness/lonellyness/depressiveness/so on… , and with female devs they shot with female stuff (Had no better way of calling it)…

          I usually ignore and move on, but i decided to give my two cents about the debate before someone break godwin’s law…

          Ah, and Lea, i love your posts, i wish you had time to post more stuff! =]

        • @JoaoBeno:disqus I agree in your description of the how comments work today. I just think it’s sad that they always have to be about (or colored by) gender. Let’s talk and joke about code instead.

        • JoaoBeno

          Sure sure, I’m just saying that they aways do that, be a male or a female coder, there is aways an troll to push us down…

        • Let’s just vote down the trolls.

        • Do you know who also tried to stop discussions with the “let’s not bring in godwin’s law” excuse? Hitler!

      • Dustin

        I’m not even sure it matters. The comment has no correlation and makes no sense at all.

      • I can’t help but wonder how the comment by gp could have possibly gotten any upvotes.

      • Best_Reviews

        He would have written something else were u a male …. my therapist says it’s typical of men with tiny peepees… so don’t worry about it, everybody gets trashed by some people, lol.

    • Maslow

      My cat, who’s therapist too, says that you wrote this comment because you have mother issues. Meow :3 (Really nice job Lea btw. Love it)

    • kerriganmarois

      I’m pretty sure gp is a piece of robot code and not a real person.

  • Pingback: Pure CSS & Simplistic Loader/Spinner » CSS 3 & HTML 5 Links und Infos()

  • Pingback: Cleanest CSS Spinner, Ever()

  • toh

    Very nice !

  • Robert North

    Very awesome! Well done – integrated it immediately into our web app.

    Scratching my head on how I might go about making the lines thinner, or longer. Trying the math in the comments, but I don’t think I understand. What is ‘part width’ and ‘part height’?

    • Part width is the thickness of the lines, which is what you want to change. You need to change 2 values to change that, from what I see. Part height is the height of the lines. Sorry for the weird terminology, but wasn’t sure what to call it!

      • Robert North

        Ahh thank you!

        That is what I thought – my problem is in using a calculator.

        Such a great contribution to a lighter and cleaner web. Thanks again.

        • Robert North

          In case anybody needs an example of making the lines thinner with Lea’s weird terminology (jokes).. here is with thinner lines:

  • Sander

    In Opera 12, the fallback text is visible and rotates with the rest of the spinner 🙂 looks really funny. Changing text-indent to -999em fixes this.
    In Opera 18, it does not rotate, which is strange because it’s based on Chromium 31 and Chrome 31 works just fine.
    Other than that: nice work! Saves a request to a GIF file (or more if you have different size spinners) and looks much better!

  • You could easily make some with 1 or 2 elements. Here are few I’ve made:

    • Using :before and :after pseudo-elements would kill the need to nest 2 to 3 elements. (Interesting loaders though)

    • I like your spinners a lot, clean code.

  • don’t eat

    Nice work! Here’s another “one-element/simple css” spinner:

    • Fábio Witt Jagnow

      Really good approach!

  • Spinners on the Internet have always been weird. People have this expectation that once their browser’s loading bar is done then everything on the page should be loaded, but when you see more things loading(usually inside some sort of block of content or iframe) then it can be jarring. This used to happen a lot with Flash, but I’m seeing a resurgance of loading bars and spinners with some single-page web apps.

    Leaving that aside, I think for most web devs two divs is small enough to be easily reusable. Especially when so many bulky frameworks require four or five divs just to make a header!

  • Nick Beranek

    This looks great, Lea. Also, I appreciate you providing alternative text for screen reader users.

  • Nice work, Lea! Though this just made me wonder why we still don’t have a JavaScript API to control the native browser progress bar/spinner.

    • Usually we don’t use JavaScript APIs to style things 😛 There is a lot of discussion in the CSS WG from time to time about styling such native elements. Hopefully, when the Shadow DOM combinators get standardized and more widely supported, it should help in this.

      • Sorry, I‘m not talking about styling, I‘m talking about starting/stopping the spinner.

  • I think it’s possible to do it with only one element if using squares to build the bars. Here’s my attempt:

    – Rounded corners;
    – Weird tiny white space between the squares in Chrome;
    – Better order of the shadows properties (for reading), or at least useful comments.

    • Chris Nager

      @LeaVerou:disqus This is fantastic! Thanks for sharing. Love your work.
      @danillonunes:disqus Great job as well! I built off of your idea by building the bars with box-shadow squares. I also addressed the three issues you said were missing.

      I had some fun with this. Check out my Zero Element CSS Spinner:

  • How’s this for simplicity?

    #spinner {
    width: 150px;height: 150px;
    -webkit-animation: sweep 1s infinite linear;
    border-bottom:5px solid blue;
    @-webkit-keyframes sweep { to { -webkit-transform: rotate(360deg); } }

    • designcouch

      That’s exactly the solution that I arrived at last year.

    • SikoSoft

      This one is definitely much cleaner than the self-proclaimed “cleanest css spinner ever”. 😛

      Actually, looking through these comments, I’ve seen several which are better. The one in the actual article itself is way too convoluted. IMHO, referring to it as a “clean” is mighty generous.

      On the bright side I only found these better ones from arriving on this page. 🙂

      Thanks for this one – it’s definitely the best I’ve ever seen!

  • crazyrohila

    If anyone using scss, I have created a scss mixin with some configurable variables for the same.

  • I definitely bookmark this page and share it with your friends, hopefully will be useful to them.

  • Pingback: Tweet Parade (no.48 Nov 2013) - Best Articles of Last Week | gonzoblog()

  • Pingback: CSS | Annotary()

  • Pingback: Collective #92 » CSS 3 & HTML 5 Links und Infos()

  • Depending on the browser support you are aiming for, you could remove the extra element by using linear-gradients only.

    • Yes, but then you can’t have the rounding unless you use tons of gradients which is worse than an extra HTML element. Removing the extra HTML element isn’t a goal in itself, it’s only a good idea if the extra CSS code involved makes sense and isn’t too long.

  • jfcarr

    Nice spinner. I just wish I could get our company off of IE9 as their main browser so that I could use neat CSS stuff like this. At least Windows XP has been 99% expunged from our network. Baby steps.

    • Hey there!
      Glad you liked it. Btw, I’m not sure if you mean that you still support IE9 or that you work with some sort of intranet apps that are all IE9, but if it’s just a %, the spinner is supposed to degrade gracefully. It won’t spin, but it will still look like a spinner, which by now is a pretty universal convention for progress.

      • jfcarr

        IE9 is the official corporate IT approved browser and only a few select users are allowed to install IE10, Chrome or other browsers. Therefore, I have to have IE9 compatibility on all intranet sites. User acceptance testing required the spinning spinner so I had to go with a Javascript solution.

  • Very light, using this in a production site that contains some global resets may allow the code to be lightened even more. Brilliant as always.

  • Really, i landed here from twitter. I will fav that to come back.

  • stephen p

    Feel so dumb, why won’t this spin in a boot strapped (2x) page?

    • Vendor prefixes.

      • Ian Simmons

        -webkit-allthethings Works great in node-webkit app. Thanks! 🙂

    • stephen p

      Turns out it’s the latest version of Canary

  • Philipp Kyeck

    Am I the only one that’s having problems seeing this?

    Chrome 31 on a Mac … Safari is working fine though.

    • TomiS

      I’m experiencing the same problem in my dev with Chrome (Firefox is ok). The demo, however, works fine with Chrome too. Can’t find reason why this happens. I’m using Twitter bootstrap 2.3.2 btw.

      • Yes the reason that its like this you have to add -webkit- Heres my code Also if you are using bootstrap i would change class name .progress is being used in bootstrap and will cause css conflicts

        @keyframes spin {
        to {
        transform: rotate(1turn);
        -webkit-transform: rotate(1turn);

        .ps-progress {
        position: relative;
        display: inline-block;
        width: 5em;
        height: 5em;
        margin: 0 .5em;
        font-size: 12px;
        text-indent: 999em;
        overflow: hidden;
        animation: spin 1s infinite steps(8);
        -webkit-animation: spin 1s infinite steps(8);
        } {
        font-size: 6px;
        } {
        font-size: 24px;

        .ps-progress > div:before,
        .ps-progress > div:after {
        content: ”;
        position: absolute;
        top: 0;
        left: 2.25em; /* (container width – part width)/2 */
        width: .5em;
        height: 1.5em;
        border-radius: .2em;
        background: #eee;
        box-shadow: 0 3.5em #eee; /* container height – part height */
        transform-origin: 50% 2.5em; /* container height / 2 */
        -webkit-transform-origin: 50% 2.5em;

        .ps-progress:before {
        background: #555;

        .ps-progress:after {
        transform: rotate(-45deg);
        -webkit-transform: rotate(-45deg);
        background: #777;

        .ps-progress > div:before {
        transform: rotate(-90deg);
        -webkit-transform: rotate(-90deg);
        background: #999;

        .ps-progress > div:after {
        transform: rotate(-135deg);
        -webkit-transform: rotate(-135deg);
        background: #bbb;

        • TomiS

          Thanks. That fixed it.

  • Pingback: Collective #92 | Web Design Factory()

  • Kidlvr

    Is there a jQuery plugin for this?

    • Why would you use a jQuery plugin for this.
      It’s easier to load the element into DOM when you need it.
      Its styling is done by CSS anyhow.

      • Kidlvr

        How do you load it into the DOM without jQuery? Should I use mootools instead?

  • Daniel Furze

    Ah this is great! Thanks, I’ll be using something like this all the time now 🙂

  • Pingback: Pure CSS & Simplistic Loader/Spinner by sugeng tigefa()

  • Pingback: Diacode Weekly #11 | Blog de Diacode()

  • Pingback: Collective #92 | Daniele Milana()

  • Pingback: Latest Apps and Tools of the Week [14th December-20th December]()

  • Pingback: Useful Tools and Websites for Designers and Developers – December 2013()

  • Pingback: The Best Tools of 2013 for Designers and Developers()

  • Pingback: 10 Fresh Handy CSS Tools for Developers | Code Geekz()

  • Pingback: 转:前端开发必备 40款优秀CSS代码编写工具推荐 | 心无境则梦无限()

  • Pingback: Theme Performance | ThemeShaper()

  • Pingback: 40款优秀CSS代码编写工具推荐 | 我是程序员()

  • Pingback: 前端开发必备 40款优秀CSS代码编写工具推荐 | 博客编程()

  • Dietrich T Miller

    this is good, but you need to make this compatible for different browsers, it currently does not work in chrome/I.E. have a look:

    • Seems to work in Chrome, just like I say in my blog post. I’m pretty sure it works in IE10, I tested it before I published this.

  • Pingback: 前端开发必备 40款优秀CSS代码编写工具推荐 - 7科技()

  • vsync

    checkout my clean spinners I wrote back in 2011 when CSS spinners where unheard of:

  • Blake Stephens

    I just discovered your site and have been really pleased and excited with a lot of your creative implementations! Great work! I was curious why the Spinner didn’t seem to be respecting the steps() timing function (in my browser, Mac Chrome v35) so I tinkered with it, and apparently for steps() to work as expected (and not just as smooth linear), you must also have a from{} in the animation definition:
    from { transform: rotate(0turn); }
    Adding that, made the stepping animation work as expected. Keep up the great work! I also really liked the angled tabs idea. Very ingenuitive. You’ve earned a new follower. 🙂

  • quby4 seems to generate css loader too, but not as neat as your work :).
    yet it has gif alternative which I believe is generated via svg.

  • Pingback: Cleanest CSS Spinner, Ever | Multipop()

  • Fancy, but using 10% cpu usage on a 2Ghz i7 octa-core for a spinner is not okay. (Chrome v39 64-bit, OS X 10.10)

  • Pingback: How to make javascript execute commands in a running manner | 我爱源码网()

  • Sauvage


    I admire your efforts, but the results aren’t quite satisfactory. I notice a wobble effect on various sizes / scaling. So I started from your project and changed the behaviour of the spinner by not spinning the actual container, but rather the opacity of each spinner element, resulting in a perfect pure javascript spinner (works on all modern browsers, including IE9+).

    Codepen demo:

  • Pingback: Michael kors outlet()

  • Pingback: rialudi()

  • Pingback: 3 Logical Alternatives to Animated GIFs - Builtvisible()

  • Bob Lee

    Loader seems awkward if I load bootstrap.css library?

  • Pingback: Stunning examples of CSS loaders | MotionBump Reader()

  • Pingback: Google()

  • Pingback: Stunning examples of CSS loaders()

  • Pingback: Magic Wand Massager()

  • Pingback: Trenda News()

  • Pingback: download apk games()

  • Pingback: free android games()

  • Pingback: male stroker()

  • Pingback: pc games free download full version for windows 10()

  • Pingback: spiderman game download for pc()

  • Pingback: Hen And Stag Nights()

  • Pingback: kala jadu()

  • Pingback: kala jadoo()

  • Pingback: лапароскопски операции()

  • Pingback: primary oral herpes outbreak()

  • Pingback: science news()

  • Pingback: e-mail database()

  • Pingback: Best Glass Dildo()

  • Pingback: nighties()

  • Pingback: Silicone Vibrator()

  • Pingback: latitude batteries()

  • Pingback: casual games for android()

  • Pingback: pokemon go free download()

  • Pingback: legit work from home jobs no fees()

  • Pingback: making money online()

  • Pingback: paintless dent removal training()

  • Pingback: full download for windows()

  • Pingback: pc games free download for windows 10()

  • Pingback: pc games free download full version for windows 10()

  • Pingback: 福井歯医者()

  • You’re awesome.

  • Pingback: 福井歯医者()

  • Pingback: בגדי הריון()

  • Pingback: research work()

  • Pingback: barrie movers and storage()

  • Pingback: Wedding photography London()

  • Pingback: free bonus slots()

  • Pingback: apple icon()

  • Pingback: pc games free download full version for windows xp()

  • Pingback: free download for windows xp()

  • Pingback: Hyundai()

  • Pingback: stalik hankishiev()

  • Pingback: love spell caster()

  • Pingback: life insurance industry()

  • Pingback: Massage Vibrator()

  • Pingback: free download for windows 10()

  • Pingback: windows games free download,free download for pc()

  • Pingback: Summer in marbella()

  • Pingback: penis sex toy()

  • Pingback: kala jadu()

  • Pingback: learn hands on cooking skills()

  • Pingback: PHP Youtube importer()

  • Pingback: Types of Vibrator()