topaxi.codes

CSS-Only Loading Mask

Sometimes in a web application, we need to mark a bit of content as loading.
Most solutions use some kind of JavaScript like jquery.loadmask, but what if we could only add a class to an element instead?

With IE 7 to 9 disappearing from the web, we can do this today with plain CSS using the ::before and ::after pseudo-elements.

In our example, we are going to use ::before for the overlay and ::after for the loading throbber.
The loading throbber will be centered using the CSS function calc() and spinning using CSS Animations.

/*
We set the element we are applying our loading mask to relative  
*/
.loading-mask {
  position: relative;
}

/*
Because we set .loading-mask relative, we can span our ::before  
element over the whole parent element  
*/
.loading-mask::before {
  content: '';
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  left: 0;
  background-color: rgba(0, 0, 0, 0.25);
}

/*
Spin animation for .loading-mask::after  
*/
@keyframes spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(359deg);
  }
}

/*
The loading throbber is a single spinning element with three  
visible borders and a border-radius of 50%.  
Instead of a border we could also use a font-icon or any  
image using the content attribute.  
*/
.loading-mask::after {
  content: "";
  position: absolute;
  border-width: 3px;
  border-style: solid;
  border-color: transparent rgb(255, 255, 255) rgb(255, 255, 255);
  border-radius: 50%;
  width: 24px;
  height: 24px;
  top: calc(50% - 12px);
  left: calc(50% - 12px);
  animation: 2s linear 0s normal none infinite running spin;
  filter: drop-shadow(0 0 2 rgba(0, 0, 0, 0.33));
}

Simple example:

<div class="loading-mask">  
  <p>I'm waiting for something...</p>
</div>  

I'm waiting for something...

Works on almost anything:

Example using a picture:

I'm waiting for something with a picture...

Caveat: You cannot use this on elements which already define ::before or ::after pseudo-elements, as they might override each other.

That's it, there are certainly more possibilities than using a border or picture, try playing around a bit :)