Skip to main content
Home / Articles /

Let’s Make a Fancy, but Uncomplicated Page Loader

It’s pretty common to see a loading state on sites these days, particularly as progressive web apps and reactive sites are on the rise. It’s one way to improve “perceived” performance — that is, making it feel as though the site is loading faster than it actually is.

There’s no shortage of ways to make a loader — all it takes is a quick search on CodePen to see oodles of examples, from animated GIFs to complex animations. While it’s tempting to build the fanciest of the fancy loaders, we can actually do a pretty darn good job with only a minimal amount of CSS and JavaScript.

Here’s an example we can make together.

See the Pen
Preloader with JavaScript FadeOut
by Maks Akymenko (@maximakymenko)
on CodePen.

SVG and CSS is all we need for the spinner

I’m going to assume that you’ve already created a project, so we’ll jump right in and start with the spinner — or “pre-loader” as it is also called.

SVG is a great option for a spinner. It’s scalable and implementing it is as easy as an image tag. We could make one from scratch, say in an image editor like Illustrator, Sketch or Figma. For this example, I’m just going to grab this one from, which is a nice resource to make and customize different loaders.

Now that we have an SVG for the visual, we can drop it into HTML:

<div class="preloader">
  <img src="spinner.svg" alt="spinner">

We’re using .preloader as a wrapper, mostly because it helps us position the image on the page, but also because it will help us hide and reveal the page content while the loader works.

Let’s style it up:

.preloader {
  align-items: center;
  background: rgb(23, 22, 22);
  display: flex;
  height: 100vh;
  justify-content: center;
  left: 0;
  position: fixed;
  top: 0;
  transition: opacity 0.3s linear;
  width: 100%;
  z-index: 9999;

This is doing a few things that are more than cosmetic:

  • We’re displaying the loader directly in the center of the screen, using flexbox properties and values.
  • We’ve made the element take up the entire width and height of the screen and given it a black (well, actually a really, really dark gray) background. That means anything behind it (like the page content) is completely hidden. If our page was a different background color (e.g. white), then we would adjust the loader’s background color accordingly.
  • The position is fixed so scrolling won’t affect it’s location on the page. Plus, the z-index is high enough that not other element should stack on top of it and block it from view.

This is what we should see so far when opening it up in the browser:

A circle loader that fades out into a black background.

Some light JavaScript handles the hiding

We’ve got a fancy spinner that covers the entire page, whether we’re viewing this on small or large screens. No we can write some logic to make it fade out after a certain amount of time. That’ll take a small dose of JavaScript.

First, let’s select the .preloader element we just styled up:

const preloader = document.querySelector('.preloader');

It would actually be a lot easier to add a class to the loader that sets its opacity to zero. However, it wouldn’t be as smooth as what we’re doing here, which is using a tiny helping of JavaScript to create a fadeOut function.

const fadeEffect = setInterval(() => {
  // if we don't set opacity 1 in CSS, then
  // it will be equaled to "" -- that's why
  // we check it, and if so, set opacity to 1
  if (! { = 1;
  if ( > 0) { -= 0.1;
  } else {
}, 100);

💡 jQuery has a function that does this right out of the box. Leverage that if you’re already using jQuery in your project. Otherwise, rolling it with vanilla JavaScript is the way to go.

Let me explain the JavaScript a little bit. As the comment says, if our .preloader element doesn’t have the opacity property set, then it will be equal to empty ("") and we can set it to a value of 1 manually to make sure it displays when the document loads.

Once we know the opacity is set, then we set manipulate it. The whole function is wrapped in setInterval and we check if the opacity property every 100 milliseconds to see if it is greater than zero. As long as it is above zero, we decrease its value in 0.1 increment, which creates a smooth effect that fades the element out over time.

Once we hit zero opacity, we clearInterval to stop the script from running infinitely. Feel free to play around with timing and decreasing points to fit your needs.

The last thing that left to do is to call the function. We’ll call it when the window loads:

window.addEventListener('load', fadeEffect);

We are intentionally using the load event instead of DOMContentLoaded because the DOMContentLoaded event is fired when the document has been completely loaded and parsed. That means it doesn’t *wait for stylesheets, images, and subframes to finish loading* *before it executes*. The load event can be used to detect a fully-loaded page, and that is exactly what we are looking for. Otherwise, the function would start before our CSS and SVG are ready.

Drop some content into the HTML and try things out. Here’s the demo again:

See the Pen
Preloader with JavaScript FadeOut
by Maks Akymenko (@maximakymenko)
on CodePen.

Congratulations! You now know how to build a pretty nice loading effect using nothing but an image and a pinch of CSS and JavaScript. Enjoy!