Last Updated: February 25, 2016
· verlok

CSS only spinner loading animation

We used GIF images to create animations for years, but they aren’t pretty to be used over gradients or pictures (no alpha channel, no anti-aliasing) of which modern web sites are full. There are many workarounds to animate PNG images instead, but…

I want to show you a solution I found to create a “loading” animation from scratch, using only CSS 3, without images.

See the results on codepen

<div class="spinner">
  <div class="b1 se"></div>
  <div class="b2 se"></div>
  <div class="b3 se"></div>
  <div class="b4 se"></div>
  <div class="b5 se"></div>
  <div class="b6 se"></div>
  <div class="b7 se"></div>
  <div class="b8 se"></div>
  <div class="b9 se"></div>
  <div class="b10 se"></div>
  <div class="b11 se"></div>
  <div class="b12 se"></div>
@import "compass/css3";

$spinnerElementColor: #000;
$startOpacity: 1;
$stopOpacity: 0.25;
$loading_duration: 0.75s;
$loading_numberOfBars: 12;
$loading_lDelay: $loading_duration / $loading_numberOfBars;

@mixin keyframes($name) {
  @-webkit-keyframes #{$name} {
  @keyframes #{$name} {

@include keyframes(fade) {
  from { @include opacity($startOpacity); }
  to { @include opacity($stopOpacity); }

.spinner {
  position: absolute;
  width: 20px;
  height: 20px;
  display: block;
  top: 50%;
  left: 50%;
  margin: -10px 0 0 -10px;

  .se {
    width: 10%;
    height: 33%;
    background: $spinnerElementColor;
    position: absolute;
    left: 44.5%;
    top: 37%;
    @include opacity(0);
    @include border-radius(50px);
    @include box-shadow(0 0 3px rgba(0,0,0,0.2));

  @for $i from 1 through $loading_numberOfBars {
    .b#{$i} {
      @include transform(rotate(#{($i - 1) * 30}deg) translate(0, -142%));
      @include animation(fade $loading_duration infinite
       ($loading_lDelay * ($i - 1)));

No js code required :)