How to Create a Skeleton Loading Using CSS

By
css
coding
ui/ux
Open in Demo.js

Modern web technology has lots of features for a better user experience. One of them is a skeleton loading component, where you can see placeholders with a gray colored shine animation before some data or images are loaded into those places. Here we are going to learn how to create one of those. Check out the following skeleton loading component, only written using CSS.

First, we can create some elements to apply skeleton loading. Below, we have just a container with two child elements. We can define its width and height so there is a visible area for the elements. We are going to use a specific CSS class name called skeleton to define our skeleton loading animation. So any element with the skeleton class will have the loading effect.

<!-- container element -->
<div class="container">
  <!-- first item with skeleton loading -->
  <div class="item-icon skeleton"></div>
  <!-- second item with skeleton loading -->
  <div class="item-text skeleton"></div>
</div>
/* container element */
.container {
  display: flex;
  gap: 10px;
}

/* first item regular rules */
.item-icon {
  width: 60px;
  height: 60px;
  border-radius: 8px;
}

/* second item regular rules */
.item-text {
  width: 120px;
  height: 60px;
  border-radius: 8px;
}

Next, we can have the skeleton CSS rules. These rules will be applied to any element we are going to have the loading animation, so that element will become the container of the skeleton.

/* skeleton element rules */
.skeleton {
  /* make child element attach absolute */
  position: relative;
  /* hide overflowing skeleton area */
  overflow: hidden;
  /* background gray color */
  background-color: #fff2;
}

Next, we have the animating portion of the skeleton, written using the after pseudo-class. This element will be sliding inside the parent element with the shining effect. Since we are using a pseudo-class, we won't need any child element to be defined for this matter.

/* skeleton animating rules */
.skeleton::after {
  /*  */
  content: "";
  /* pseudo element absolute attachment */
  position: absolute;
  /* cover full element area */
  inset: 0;
  /* place shining outside */
  transform: translateX(-100%);
  /* shine gradient background */
  background: linear-gradient(90deg, transparent, #fff7, transparent);
  /* shimmer animation options */
  animation: skeleton-animation 1.2s infinite;
}

Finally, we have the shimmer or shining animation. We just need to change the translateX position so we will see the sliding animation inside the skeleton element.

/* shimmer animation */
@keyframes skeleton-animation {
  100% {
    transform: translateX(100%);
  }
}

If we are going to apply this to an actual scenario, for example, like an image with skeleton loading, we can use JavaScript to load the images first, replace them with a placeholder, and remove the skeleton class name. Assume that the placeholder elements have the real image URL on their data-src custom attribute.

// get all elements with image placeholders
const elements = document.querySelectorAll(".image-placeholder")

// for each element
for (let i = 0; i < elements.length; i++) {
  // get current element
  const element = elements[i]
  // create an image element
  const image = new Image()
  // image load listener
  image.addEventListener("load", () => {
    // set full class name to image element
    image.className = element.className
    // remove skeleton class name
    image.classList.remove("skeleton")
    // replace placeholder with image
    element.replaceWith(image)
  })
  // set image src to start loading
  image.src = element.getAttribute("data-src")
}