Page loader with pure CSS

Andrey Zakharov

Gold old days

The modern front-end is very interactive and dynamic. Just few years ago (OMG, it was 10 years ago already, I think) pages rendered from a server, so browser had all rights and obligations to check and show current progress of loading. Now this is a responsibility of front-end developers. We load a lot of data asynchronously just on the place and we want to make user experience comfort as much as he is staring at our cool fashion spinner while page loading. So, how many developers we have, so many solutions exist. Usually, we use some js events to check if page is ready to display. Today I will show you a very powerful and simple way to show loader of the whole page or a particular part with asynchronous data without using javascript at all.

So, let’s talk about our problem. Until desired data is loaded, we have some elements which are empty yet and usually look ugly. So, we want to hide such empty elements and show nice loader instead. The “emptiness” of html elements is actually just a property of appearance. So, we can predict that it should be a css selector which can describe such property of element. And it is!

Let me introduce the :empty css selector.

Oh man, I need to support IE6…

To prevent you from immediate scrolling down to check what is the cross-browser support for this selector, I give it to you right here. So, according to the w3 standarts the compatible is pretty good (until you need to support IE6, but hey, you know, only God can help you in such case):

Ok, gimme some practice!

Let’s start with a very simple example, just to have a proof of concept. Create a html page with a primary content element and loader placeholder.

<div id="page-content"></div>
<div id="loader"></div>

Of course, #page-content may contain another empty (or already rendered) elements, but you will manage it, right? You just need any empty element on your page which will be filled after all. For our small example let’s make an agreement that we have an empty #page-content element. The loader should be hidden usually. So just hide it:

#loader {
    display: none;

And obviously, we should show loader when our page content is empty yet:

#page-content:empty + #loader {
    display: block;

To see our cool loader in action we should load some data into our content element. Not long thinking, I invented my super content loading system:

setTimeout(function() {
    document.getElementById("page-content").textContent = 'Page is ready!';
}, 2000);

When open the page you will see the “Loading…” text for 2 seconds (3 seconds is already too long for me!) and “Page is ready!” after that. Not bad, right? At least we know that our idea works and we can spend time now on some prettifying.

More CSS!

The exact way how to build modern loader is not a topic of this post, but just to give you an idea what to do next, let’s make some animation here. The idea is that we have a loader on a semitransparent wrapper. When page is ready, the loader will smoothly disappear.

#loader {
    opacity: 0;
    transition: z-index 1s step-end, opacity .8s ease-in-out;
    position: fixed;
    height: 100%;
    width: 100%;
    top: 0;
    left: 0;
    background: rgba(0, 0, 0, 0.4);
    z-index: -1;

#page-content:empty + #loader {
    opacity: 1;
    z-index: 100;

Pretty easy, as you see. Now you can place a spinner inside #loader element and position it on the center. So it will become just a common modern loader. As you can guess, you may also use such loader along with any empty element on the page. Let’s say we don’t care of the whole page, but we have a list which will be rendered after async request will be completed. So, just the same idea:

<ul class="example-list"><ul>
<span class="local-loader">Please, wait...<span>

Your lovely framework likely supports conditional rendering such as “if” and “for”, which means that some elements (<li> items in “for” loop, for example) will be hidden until data will be presented, which is totally the way to use our approach. Have a nice coding!


you might also like