Pure CSS Loading Spinners

Nobody likes waiting for things to load, but with some creative spinner effects you can help to make the wait a little less boring. In this tutorial we're going to look at how you can create some advanced spinners using only CSS.

View Demo

Effects

A note on browser support

Before we get started it's worth pointing out that alot of these effects use the latest CSS3 techniques such as manipulating elements in a 3d-space - browser support is generally very good though the latest vesion of IE (at time of writing IE11) still doesn't support Preserve-3d for some of the more advanced effects.

The Code

In the code examples below we'll look at the HTML and CSS for each effect. Effects are created using keyframes, note that in the interest of space only @keyframe code is shown, but for full compatability you will also need the -webkit-keyframes, see the demo source code if you're not familiar with this.

All effects use an infinate loop for the animations.

1 - Exploding Sqaures

View the animations on the demo page.

HTML

The markup comprises of a container, and four boxes to make each exploding element.

<div class="animation-1">
    <div class="box1"></div>
    <div class="box2"></div>
    <div class="box3"></div>
    <div class="box4"></div>
</div>

CSS

For the exploding square we rotate the containing box and then individually animate the four child boxes to rotate and translate (move a number of pixels to a new location). The percentages in the keyframes represent what styling the elements should have when they reach that point in the animation (e.g. at 40% of a 2 second animation).

.animation-1
{
    width:55px;
    transform: rotate(45deg);
    -webkit-transform: rotate(45deg);
    -ms-transform:rotate(45deg);
}

.animation-1 div
{
    display:inline-block;
    background-color: #0088d0;
    width:25px;
    height:25px;
    margin:0;
    padding:0;
}

.animation-1 .box1
{
    -webkit-animation: animation1-box1 1.5s infinite;
    animation: animation1-box1 2s infinite;
}

.animation-1 .box2
{
    -webkit-animation: animation1-box2 1.5s infinite;
    animation: animation1-box2 2s infinite;
}

.animation-1 .box3
{
    -webkit-animation: animation1-box3 1.5s infinite;
    animation: animation1-box3 2s infinite;
}

.animation-1 .box4
{
    -webkit-animation: animation1-box4 1.5s infinite;
    animation: animation1-box4 2s infinite;
}

@keyframes animation1-box1
{
    40%
    {
        transform: translate(-25px, -25px) rotate(85deg);
    }
    50%
    {

        transform: translate(-25px, -25px) rotate(90deg);
    }
    100%
    {
        transform: translate(-0px, -0px) rotate(180deg);
    }
}


@keyframes animation1-box2
{
    40%
    {
        transform: translate(50px, -25px) rotate(85deg);
    }
    50%
    {
        transform: translate(50px, -25px) rotate(90deg);
    }
    100%
    {
        transform: translate(-0px, -0px) rotate(180deg);
    }
}

@keyframes animation1-box3
{
    40%
    {
        transform: translate(-50px, 25px) rotate(85deg);
    }
    50%
    {
        transform: translate(-50px, 25px) rotate(90deg);
    }
    100%
    {
        transform: translate(-0px, -0px) rotate(180deg);
    }
}


@keyframes animation1-box4
{
    40%
    {
        transform: translate(25px, 25px) rotate(85deg);
    }
    50%
    {
        transform: translate(25px, 25px) rotate(90deg);
    }
    100%
    {
        transform: translate(-0px, -0px) rotate(180deg);
    }
}

2 - Collapsing Squares

Collapsing Squares

HTML

The markup for the second loader is the same as the first comprising of one container and four children. The child boxes will all collapse into box 3.

<div class="animation-2">
    <div class="box1"></div>
    <div class="box2"></div>
    <div class="box3"></div>
    <div class="box4"></div>
    <div class="box5"></div>
</div>

CSS

Boxes 1,2,4 and 5 all move inward toward box three, while box three scales up creating the effect that the boxes are being combined.

.animation-2
{
    width:145px;
}

.animation-2 div
{
    display:inline-block;
    background-color: #0088d0;
    width:25px;
    height:25px;
    margin:0;
    padding:0;
    border-radius:2px;
}

.animation-2 .box1
{
    -webkit-animation: animation2-box1 1.5s infinite;
    animation: animation2-box1 1.5s infinite;
}

.animation-2 .box2
{
    -webkit-animation: animation2-box2 1.5s infinite;
    animation: animation2-box2 1.5s infinite;
}

.animation-2 .box3
{
    -webkit-animation: animation2-box3 1.5s infinite;
    animation: animation2-box3 1.5s infinite;
}

.animation-2 .box4
{
    -webkit-animation: animation2-box4 1.5s infinite;
    animation: animation2-box4 1.5s infinite;
}

.animation-2 .box5
{
    -webkit-animation: animation2-box5 1.5s infinite;
    animation: animation2-box5 1.5s infinite;
}

@keyframes animation2-box1
{
    40%
    {
        transform: translate(50px, 0) scale(1.5);
    }
    100%
    {
        transform: translate(0, 0);
    }
}

@keyframes animation2-box2
{
    40%
    {
        transform: translate(25px, 0) scale(2);
    }
    100%
    {
        transform: translate(0, 0);
    }
}

@keyframes animation2-box3
{
    25%
    {
        transform: scale(3);
    }
    100%
    {
        transform: scale(1);
    }
}



@keyframes animation2-box4
{
    40%
    {
        transform: translate(-25px, 0) scale(2);
    }
    100%
    {
        transform: translate(0, 0);
    }
}

@keyframes animation2-box5
{
    40%
    {
        transform: translate(-50px, 0) scale(1.5);
    }
    100%
    {
        transform: translate(0, 0);
    }
}

3 - Rotating Cube

HTML

No doubt the trickier of all the effects as we need to create a 'cube' effect that uses 3d perspective.  To achieve this we create 6 child divs representing each of the cube faces, and then orientate them into position using rotate and translateZ (moving elements closer or further away from the viewer). 

<div class="animation-3">
    <div class="cube">
        <div class="face face1"></div>
        <div class="face face2"></div>
        <div class="face face3"></div>
        <div class="face face4"></div>
        <div class="face face5"></div>
        <div class="face face6"></div>
    </div>
</div>

CSS

Perspective is applied to the outer division to create a 3D-space. With the faces of the cube in place we then simply use a x rotation animation on an infinite loop. The animation is broken down into three steps to give an effect that the cube pauses momentarily. 

.animation-3
{
    -webkit-perspective: 1000;
    -webkit-perspective-origin: 50% 20px;
    perspective: 1000;
    perspective-origin: 50% 20px;
    width:36px;
}

.animation-3 .cube
{
    position: relative;
    margin: 0 auto;
    height: 36px;
    width: 36px;
    -webkit-transform-style: preserve-3d;
    transform-style: preserve-3d;
}

.animation-3 .face
{
    position: absolute;
    height: 36px;
    width: 36px;
    padding: 2px;
    background-color: #0088d0;
    opacity:0.6;
}

.animation-3 .face1
{
    -webkit-transform: rotateX(90deg) translateZ(20px);
    transform: rotateX(90deg) translateZ(20px);
}

.animation-3 .face2
{
    -webkit-transform: translateZ(20px);
    transform: translateZ(20px);
    background-color: #222;
}

.animation-3 .face3
{
    -webkit-transform: rotateY(90deg) translateZ(20px);
    transform: rotateY(90deg) translateZ(20px);
}

.animation-3 .face4
{
    -webkit-transform: rotateY(180deg) translateZ(20px);
    transform: rotateY(180deg) translateZ(20px);
    background-color: #222;
}

.animation-3 .face5
{
    -webkit-transform: rotateY(-90deg) translateZ(20px);
    transform: rotateY(-90deg) translateZ(20px);
}

.animation-3 .face6
{
    -webkit-transform: rotateX(-90deg) translateZ(20px) rotate(180deg);
    transform: rotateX(-90deg) translateZ(20px) rotate(180deg);
    background-color: #005AA2;
}
.animation-3 .cube
{
    -webkit-animation: animation3 5s infinite;
    animation: animation3 5s infinite;
}

@keyframes animation3
{
    40%
    {
        transform:  rotateX(180deg);
    }
    60%
    {
        transform:  rotateX(190deg);
    }
    100%
    {
        transform:  rotateX(360deg);
    }
}

4 - Spinning Circles

Another tricky effect as the circles are spinning while on rotation, also using a 3d-space. For a detailed breakdown of how the flip effect works see the CSS Flip Effect tutorial

HTML

Each circle is listed as a 'card' which has a front and reverse side that is flipping while the rotation takes place.

<div class="animation-4">
    <div class="flip-cards card1">
        <div class="front-card"></div>
        <div class="reverse-card"></div>
    </div>

    <div class="flip-cards card2">
        <div class="front-card"></div>
        <div class="reverse-card"></div>
    </div>

    <div class="flip-cards card3">
        <div class="front-card"></div>
        <div class="reverse-card"></div>
    </div>

    <div class="flip-cards card4">
        <div class="front-card"></div>
        <div class="reverse-card"></div>
    </div>

    <div class="flip-cards card5">
        <div class="front-card"></div>
        <div class="reverse-card"></div>
    </div>

    <div class="clear"></div>
</div>

CSS

The flip side of each card (circle), is set to backface-visibility hidden and rotated 180 degrees so it's not visible to start with. As the cards are rotated one of the faces becomes visible and the other dissapears. There are two transitions, one to rotate the containing div, and another to flip all the cards. 

.animation-4
{
    position:relative;
    -webkit-perspective:1000;
    perspective:1000;
    -webkit-animation: animation4 4s infinite;
    animation: animation4 4s infinite;
    width:150px
}

.animation-4 .flip-cards div
{
    width:25px;
    height:25px;
    position:absolute;
    border-radius:15px;
    backface-visibility: hidden;
    -webkit-backface-visibility: hidden;
}

.animation-4 .flip-cards
{
    width:25px;
    height:25px;
    position:relative;
    float:left;
    margin-left:5px;
    -webkit-transform-style: preserve-3d;
    transform-style: preserve-3d;

}

.animation-4 .front-card
{
    z-index: 2;
    background-color: #0088d0;
}

.animation-4 .reverse-card
{
    -webkit-transform: rotateY(180deg);
    transform: rotateX( 180deg );
}

.reverse-card
{
    background-color: #005AA2;
}


@keyframes animation4
{
    40%
    {
        transform: rotate(360deg);
    }
}

.animation-4 > div
{
    -webkit-animation: animation4-card 4s infinite;
    animation: animation4-card 4s infinite;
}


@keyframes animation4-card
{
    40%
    {
        transform: rotateY( 360deg );
    }
}

5 - Expanding Lines

HTML

This more traditional animation simply has 5 bars inside a container for the markup.

<div class="animation-5">
    <div class="bar bar1"></div>
    <div class="bar bar2"></div>
    <div class="bar bar3"></div>
    <div class="bar bar4"></div>
    <div class="bar bar5"></div>
</div>

CSS

Each bar scales to twice it's length over a 1 second period, bars are increasingly delayed by 0.1 seconds to create the wave effect.

.animation-5
{
    width:117px;
    height: 50px;
}

.animation-5 div
{
    height:30px;
    width:10px;
    background-color: #005AA2;
    display:inline-block;
    margin-right:10px;
    -webkit-animation: animation5-bar 1s infinite;
    animation: animation5-bar 1s infinite;
}

.animation-5 .bar1
{
    -webkit-animation-delay: 0.5s;
    animation-delay: 0.5s;
}
.animation-5 .bar2
{
    -webkit-animation-delay: 0.6s;
    animation-delay: 0.6s;
}
.animation-5 .bar3
{
    -webkit-animation-delay: 0.7s;
    animation-delay: 0.7s;
}
.animation-5 .bar4
{
    -webkit-animation-delay: 0.8s;
    animation-delay: 0.8s;
}
.animation-5 .bar5
{
    -webkit-animation-delay: 0.9s;
    animation-delay: 0.9s;
}

@keyframes animation5-bar
{
    30%
    {
        transform: scaleY(2);
    }
}

6 - Bouncing Ball

HTML

Not much markup for this one, a container, a ball and it's shadow.

<div class="animation-6">
    <div class="ball"></div>
    <div class="shadow"></div>
</div>

CSS

This effect comprises of two animations, one to move the ball up and down (translate), and another to expand the shadow (scale). The ball animation is split over four phases to create a convincing 'bounce' effect.

.animation-6
{
    position:relative;
    width:20px;
}
.animation-6 .ball
{
    position:absolute;
    border-radius:15px;
    height:20px;
    width:20px;
    margin-bottom:-5px;
    background-color:#0088d0;
    -webkit-animation: animation6 1s ease-in-out infinite;
    animation: animation6 1s ease-in-out infinite;
    z-index:2;
    top:-13px;
    left:5px;
}

@keyframes animation6
{

    20%
    {
        transform: translate(0,-40px);
    }
    35%
    {
        transform: translate(0,-45px);
    }
    90%
    {
        transform: translate(0,-50px);
    }
    95%
    {
        transform: translate(0,-40px);
    }

}

.animation-6 .shadow
{
    position:absolute;
    -webkit-animation: animation6-shadow 1s infinite;
    animation: animation6-shadow 1s infinite;
    width:30px;
    height:15px;
    border-radius:15px / 7px;
    background-color:#005AA2;

}

@keyframes animation6-shadow
{
    70%
    {
        transform:  scale(0.5);
        opacity:0.5;
    }
    100%
    {
        transform:  scale(0.4);
        opacity:0.4;
    }
}

7 - Newton's Cradle

HTML

An old classic. To re-create Newton's Cradle effect we use 5 child divisions for each ball.

<div class="balls">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>

CSS

This effect requires two animations, one for the far left ball, and one for the far right ball. The last ball has it's animation delayed by half a second to give the effect of one ball forcing the next animation. To give a more convincing rocking effect the animation is split into three phases so that it can gain momentum.

.animation-7
{
    width:100px;
    margin:auto;

}
.animation-7 .balls div
{

    background-color:#005AA2;
    width:20px;
    height:20px;
    border-radius:15px;
    display:inline-block;
    margin:-2px;
    padding:0;

}

.animation-7 .balls div:first-child
{
    -webkit-animation: first-ball ease-in-out 1s infinite;
    animation: first-ball ease-in-out 1s infinite;
}

@keyframes first-ball
{
    15%
    {
        transform: rotate(36deg) translateX(-40px);
    }
    25%
    {
        transform: rotate(45deg) translateX(-50px);
    }
    50%
    {
        transform: rotate(0deg) translateX(0px);
    }
}

.animation-7 .balls div:last-child
{
    -webkit-animation: last-ball ease-in-out 1s infinite;
    -webkit-animation-delay: 0.5s;
    animation: last-ball ease-in-out 1s infinite;
    animation-delay: 0.5s;
}

@keyframes last-ball
{
    15%
    {
        transform: rotate(-36deg) translateX(40px);
    }
    25%
    {
        transform: rotate(-45deg) translateX(50px);
    }
    50%
    {
        transform: rotate(0deg) translateX(0px);
    }
}

Credits

The CSS for creating a cube effect was helped by Paul Hayes' animated cube tutorial. Inspiration for some of the animations was taken from the CoDrops gif animations.

Sign Up

NEXT: Create a CSS card flip effect on hover

In this tutorial we'll be looking at creating a card flipping transition using CSS transform in a 3d space.

comments powered by Disqus
Sign Up

Popular Tags

350x250

Need a web developer?

If you'd like to work with code synthesis on your next project get in touch via the contact page.