Show a loading bar when the page is loading

Loading...

I was working on a web app recently and I noticed that every time I clicked on a link, I couldn't tell if the next page was loading or not. On desktop browsers it was obvious enough with the browser queue, but not so much on mobile. So I decided to add a loading bar to let the user know.

Animation CSS:

<style>
@keyframes page-load {
    from {
        width:0;
    }
    to {
        width:100%;
    }
}
.page-loading::before {
    content:" ";
    display:block;
    position:fixed;
    z-index:10;
    height:2px;
    width:100%;
    top:0;
    left:0;
    background-color:#06D;
    animation: page-load ease-out 2s;
}
</style>

Creating the bar in CSS is easy enough. The bar just has to grow from 0 to 100%. But figuring out the logic on when to show the bar was a challenge. So here are the different solutions I tried:

1. On anchor tag click

My first attempt was to add an event handler on every link on the page. Clicking on them would add a class on the body and would animate a loading bar similar to the one you see below.

sample page

Javascript Code:

var links = document.getElementsByTagName("a"),
i = 0, l = links.length,
body = document.body;

for(;i<l;i++) {
    links[i].addEventListener("click",function(){
        body.className = "page-loading";
    },false);
}

This worked perfectly at first but then I realized that I had some anchor tags on the page the trigger javascript or an ajax request. This meant that the animation was triggered all the time and the loading bar is left on the top.

2. On click animate then remove.

I decided that it was fine to run the animation on every link click as long as the animation is removed right after. So I added a timer to remove the animation 3 seconds later.

for(;i<l;i++) {
    links[i].addEventListener("click",function(){
        body.className = "page-loading";
        setTimeout(function(){
            body.className = "";
        },3000);
    },false);
}

This solution worked for my case, but I couldn't help but think that it is messy. It looks more like a hack then a permanent solution. If the next page takes more than 3 seconds to load, the animation is removed and it confuses the user. Also, when the bar fills the length of the page, the user thinks the page is done loading, while that's not the case. It's just an animation. So I decided to change from a growing loading bar to a full bar in flickering colors.

<style>
@keyframes page-load {
    from {
        background-color: #ffc422;
    }
    to {
        background-color: #c0392b;
    }
}
</style>
sample page

This looks much nicer, but we still have to remove the bar 3 seconds later, which is messy. So let's explore my final solution.

Final Solution: onbeforeunload Event

This is the most elegant solution. Adding event handler to every single button is too much overhead. Instead here, we add a single event onbeforeunload to the page and when a user clicks on a link we can add our loading bar to the page.

window.addEventListener("beforeunload",function(e){
    document.body.className = "page-loading";
},false);

This will not be triggered on ajax calls or on button clicks that don't cause the whole page to unload. So we also don't need to add a timeout to remove the bar at some point. The bar will be removed when the next page is ready to load.

For my case I placed the CSS in a media query that only displays on mobile browsers but I think it can be a convenient feature to let the user know that the page is loading.

Final CSS Code:

@keyframes page-load {
    from {
        background-color: #ffc422;
    }
    to {
        background-color: #c0392b;
    }
}
.page-loading::before {
    content:" ";
    display:block;
    position:fixed;
    z-index:10;
    height:2px;
    width:100%;
    top:0;
    left:0;
    background-color:#06D;
    animation: page-load infinite ease-out 2s;
    box-shadow:0 2px 2px rgba(0,0,0,.2);
}

Final JavaScript:

window.addEventListener("beforeunload",function(e){
    document.body.className = "page-loading";
},false);

I hope you find it useful as well.


Comments

There are no comments added yet.

Let's hear your thoughts

For my eyes only