Introduction

In the previous chapter we improved our lazy loader by preventing it from resizing out of nowhere i.e stopped the reflow of the document and even made the images responsive using padding-bottom. We'll carry on with this improvement process, where now it's time to see how to give the loader the feel of loading....

So let's begin!

Choices for an icon

Loading icons are simply some sort of animated icons that indicate something is loading.

We'll incorporate them into our lazy loader to serve this very purpose. And to give a loading icon we have quite a few ways as listed below - we'll go over each one seperately in detail.

  1. Animated GIF images
  2. Still images to be animated in CSS
  3. HTML and CSS driven icons

Animated GIF images

The easiest and the quickest method to giving a loading icon is to use a ready-made, animated GIF image. The advantage with this is that we would only have to place the image in the background of .lazy, without having to animate it using any sort of CSS code.

Talking about where to get animated gif icons, there are many resources online to download numerous of them. Some are free while some are paid. One of them is Preloaders; offering both both free and paid icons and giving you the ability to customise them to match your requirements.

Apart from this we can also make a gif image on our own when we want an icon unique and local to our brand.

Anyways we'll use the following gif image for demonstrating this first choice in the list of the ways of giving loading icons.

Loading icon

Consider the following CSS to add the icon to the background of .lazy and centralising it there:

.lazy {
    background-image: url("loader.gif");
    background-position: center;
    background-repeat: no-repeat
}

background-image gives a background image, background-position: center centralises it and background-repeat: no-repeat prevents the image, by default, from repeating.

Animated GIF Loader

Still images animated in CSS

What if we don't want to go with an animated GIF, but instead with a nice looking spinner icon, or any other such image? Well we can use a CSS animation to animate the icon.

Compared to the previous one, this method is definitely more work-intensive and thought-intensive in terms of its code but comes at the benefit of being able to play in a ton of ways with the loader icon.

Starting with what comes to mind first- we can have a tricircle icon moving up and down in the background. The movement can be easily accomplished using a CSS animation and animating let's say background-position-y.

.lazy {
    background-image: url("icon.gif");
    background-position: center;
    background-repeat: no-repeat;
    animation: loader 1s linear infinite;
}

The keyframes for the animation go as follows:

@keyframes loader {
    25% {background-position-y: calc(50% - 15px)}
    50% {background-position-y: center}
    75% {background-position-y: calc(50% + 15px)}
    100% {background-position-y: center}
}

calc(50% - 15px) takes the icon upwards by 15px from the center position whereas calc(50% - 15px) takes it to the bottom from the center position. There is nothing as such in CSS: center + 15px; hence we resort back to the function calc().

This example was fairly easy to understand since the background image we chose could've been animated up and down using background-position-y properties. However the keyframes we've given in this case don't look that professional.

We can improve the animation by shifting the image from the background-image in CSS to img in HTML. And in doing things will get a bit more involved, as we will demonstrate with the spinner icon.

Ideally we need to rotate a spinner, but we can't do that at least if the icon is giving using background-image. There is simply no way to rotate background images in CSS.

So what we can do instead is to give the icon using <img> instead of background-image and append the created element to every .lazy container using DOM methods. In this way we will be able to animate the loading icon using CSS animations in any way - translation, rotation etc.

Likewise let's see how will we append the icon to our lazy image.

var loader = document.createElement("span");
loader.innerHTML = '<img src="icon.gif">';
loader.className = 'loader';
lazyCont.appendChild(loader);

Start by creating a span element (line 1); add the loading image in it (line 2); give the span element a class name to be able to style it easily (line 4); and finally append it to .lazy (line 5) - so simple!

The class .loader will help us in animating and centering the icon inside the .lazy container. Let's see how both of them are done.

How can we centre the span element .loader inside .lazy?

(All the following properties apply to .loader.)

Using vertical-align: center
Using translate(-50%, -50%), left: 100% and top: 100%
Using background-position: center

To centralise the .loader element in its parent we can use translate(), and the properties left and right; whereas to animate it we will use rotate() to spin it around.

But the problem with using translate() is that is has to go into the transform property, where we need to include yet another function rotate(). Managing two functions in transform is not bad, but even not that good. So why not try to find some way to only include rotate() in the keyframes?

So the cut-off is that we shouldn't ideally use transform in centralising our .loader element. And following we do just that:

.loader {
    top: 50%;
    left: 50%;
    position: absolute
}
.loader img {
    margin-left: -50%;
    margin-top: -50%;
    position: relative;
    animation: spin 1s linear infinite;
}

From lines 2-4 we simply position the .loader close to the center of .lazy. Notice that we said close - the icon is not yet at the center.

To bring it to the center we bring it backwards and upwards by half of its width and height respectively as shown in lines 7-8 using margin-left and margin-top.

And we successfully centralised the icon without even touching transform; how good this trick is! Over to animating the icon, which is pretty straightforward.

@keyframes spin {
    from {transform: rotate(0deg)}
    to {transform: rotate(360deg)}
}

But not over yet - if we leave at this point - when the image loads the icon remains still there, animating. How to rectify this?

Simply hide the icon using display: none once the image loads.

lazyImage.onload = function() {
    loader.style.display = "none";    
}
Try out your lazy loader without this code and see how the icon remains in its position.

Image and CSS Loader

HTML and CSS driven icon

The last thing we can experiment with is to make a loading icon entirely in using HTML and CSS. The idea is that we will simply append the markup for the icon inside .loader and write some CSS code to animate it!

An example is shown below:

var loader = document.createElement("span");
loader.innerHTML = '<div class="icon"><span></span><span></span><span></span></div>';
loader.className = 'loader';
lazyCont.appendChild(icon);
Here we have given the loading icon a class name .icon. We could've done this with the image examples above to remain consistent in terms of the HTML.
.loader .icon span {
    display: inline-block;
    height: 15px;
    width: 15px;
    margin: 5px;
    background-color: black;
    border-radius: 15px;
    position: relative;
    animation: zoom 1s ease-in-out infinite;
}
.loader .icon span:nth-child(2) {
    animation-delay: 0.1s
}
.loader .icon span:nth-child(3) {
    animation-delay: 0.2s
}
@keyframes zoom {
    0% {transform: scale(1)}
    50% {transform: scale(0)}
    100% {transform: scale(1)}
}

And now you can check out this code in action.

HTML and CSS Driven Loader

In short, the choice for the loading icon is seriously all ours; what ever we like will be what we incorporate.