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>

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 :)