Build a Pixel Perfect Skeleton Loader Using CSS 🚀

Ram Maheshwari ♾️ - Sep 15 '21 - - Dev Community

Skeleton Loaders are used very commonly in Modern Websites/Apps to indicate loading of data instead of using the traditional loaders, spinners, etc. which are boring and can lead to Poor User Experience 😵‍💫


I created this tutorial to share my knowledge of how to create a Perfect Skeleton Screen that looks like the exact replica of the original element 😉


We are going to convert the Food Blog Card to it's own Skeleton loader as shown in the GIF below 🖼️

Skeleton Loader Preview Demo


There are 3 Steps to creating a perfect Skeleton Screen 🤘


Step 1:

Make sure you already have implemented the HTML and CSS for the Original Element. In our case, I have included the code for the Food Blog Card below.

HTML Code ⬇️

<!DOCTYPE html>
<html lang="en">
  <head>
    <link
      href="https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@400;600;700;900&display=swap"
      rel="stylesheet"
    />
  </head>

  <body>
    <div class="container">
      <div class="card">
        <div class="img-cont">
          <img
            class="img"
            src="https://images.unsplash.com/photo-1594398028856-f253a046f417?ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&ixlib=rb-1.2.1&auto=format&fit=crop&w=1189&q=80"
            alt="Food image"
          />
        </div>
        <div class="user-info">
          <div class="user-avatar-cont">
            <img
              src="https://i.ibb.co/JzNYHV9/image-1.jpg"
              alt="User Image"
              class="user-avatar-img"
            />
          </div>
          <div class="user-details">
            <div class="user-name"><span>Natalia Rodrigues</span></div>
            <div class="user-profession"><span>Food Blogger</span></div>
          </div>
        </div>
      </div>
    </div>
  </body>
</html>

Enter fullscreen mode Exit fullscreen mode

CSS Code ⬇️

      * {
        margin: 0;
        padding: 0;
        box-sizing: border-box;
      }

      html {
        font-size: 62.5%;
      }

      body {
        font-family: 'Source Sans Pro', sans-serif;
        display: flex;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
        background: #eee;
      }

      .card {
        background: #fff;
        position: relative;
        padding: 2rem;
        border-radius: 5px;
        box-shadow: 0 10px 100px rgba(0, 0, 0, 0.1);
        width: 45rem;
        overflow: hidden;
      }

      .img-cont {
        height: 30rem;
        margin-bottom: 2rem;
        border-radius: 5px;
        overflow: hidden;
      }

      .img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }

      .user-info {
        display: flex;
        align-items: center;
      }

      .user-avatar-cont {
        width: 6rem;
        height: 6rem;
        margin-right: 2rem;
        border-radius: 50rem;
        overflow: hidden;
      }

      .user-avatar-img {
        width: 100%;
        height: 100%;
        object-fit: cover;
      }

      .user-details {
        flex-grow: 1;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
      }

      .user-name {
        font-size: 2.2rem;
        margin-bottom: 5px;
        color: #444;
        text-transform: uppercase;
        letter-spacing: 1px;
        font-weight: 600;
      }

      .user-profession {
        font-size: 1.3rem;
        color: #999;
        border-radius: 2px;
        text-transform: uppercase;
        letter-spacing: 1px;
        font-weight: 600;
      }
Enter fullscreen mode Exit fullscreen mode

Result ⬇️

Food Blog Result Demo


Step 2:

Now we have to convert the card into its own Skeleton Version. To do that, I will add an extra class called card--skeleton on the HTML div with the class called card as shown below so we can target the elements inside the card.

      <div class="card card--skeleton">
Enter fullscreen mode Exit fullscreen mode

Now, we have 2 Images inside the card, the 1st image is the image of the Pizza and the 2nd Image is the image of the Person. Both of these images are wrapped inside their own container and those containers have their specific height.

Now, we will remove both of these images.

    <div class="card">
      <div class="img-cont">
        <!-- Removed Image -->
      </div>
      <div class="user-info">
        <div class="user-avatar-cont">
          <!-- Removed Image -->
        </div>
        <div class="user-details">
          <div class="user-name"><span>Natalia Rodrigues</span></div>
          <div class="user-profession"><span>Food Blogger</span></div>
        </div>
      </div>
    </div>
Enter fullscreen mode Exit fullscreen mode

And we will add a background color to the image containers as shown below using the skeleton class.

.card--skeleton .img-cont {
  background: #eee;
}

.card--skeleton .user-avatar-cont {
  background: #eee;
}
Enter fullscreen mode Exit fullscreen mode

So the end result will look like this ⬇️

Skeleton Loader Preview Demo

We will do the same thing with User Name and User Profession elements. We will change the background color of both of these elements along with the text color inside it. The background color and the text color will be the same.
I have also added some border-radius which is optional.

.card--skeleton .user-name span,
.card--skeleton .user-profession span {
  background: #eee;
  color: #eee;
  border-radius: 5px;
}
Enter fullscreen mode Exit fullscreen mode

Now, the end result will look like this ⬇️

Skeleton Loader Preview Demo

Looking cool, right? 😉

So, now we can move on to the 3rd Step where we will add the shining effect animation ⚡


Step 3:

In this step, we will add the Shining Effect Animation on the entire Skeleton Card.

To implement that, we will target the before sudo class of card--skeleton as shown below.

      .card--skeleton::before {
        content: '';
        position: absolute;
        background: linear-gradient(
          90deg,
          transparent,
          rgba(255, 255, 255, 0.9),
          transparent
        );
        width: 50%;
        height: 100%;
        top: 0;
        left: 0;
      }
Enter fullscreen mode Exit fullscreen mode

So, we have added the before sudo element which is absolutely positioned and has the same height as the card--skeleton and has 50% width of the class--skeleton.

We also added linear-gradient as the background with 3 colors ( transparent color, white color, transparent color ) in the right direction.

So, it will make our card--skeleton look like this ⬇️

Skeleton Loader Preview Demo

Now we will use CSS keyframes to move the gradient from the left side to the right side. Inside keyframes, we will target the transform property to skew ( basically to turn the linear gradient from | to / ) the element and to translate it in the X-direction.

I have already added the overflow: hidden value to the card element so when the before element goes outside of the card boundaries because of the keyframes transform, it's not going to be visible outside of the boundaries of card which is what we need.

      @keyframes loading {
        0% {
          transform: skewX(-10deg) translateX(-100%);
        }
        100% {
          transform: skewX(-10deg) translateX(200%);
        }
      }

      .card--skeleton::before {
        ...
        /* Refer the Keyframe inside the Animation */
        animation: loading 0.6s infinite;
      }

Enter fullscreen mode Exit fullscreen mode

So, the end result will finally look like this ⬇️

Skeleton Loader Preview Demo

and that's what we wanted 🥳🤘
I hope you find this post to be helpful and thanks for reading it 😇


Important 😸

I regularly post useful content related to Web Development and Programming on Linkedin and Twitter. You should consider Connecting with me or Following me on these Platforms.

Linkedin Profile, Twitter Profile


P.S. ✌️

I recently created one OpenSource Project which is a Portfolio Website Template for Developers called Dopefolio and wrote an Article about it on dev.to.

Feel free to check the article here 😄


Please React with ❤️ + 🦄 + 🔖 , As it takes time to create such content so it will be very helpful if you show some love to this post.

Share your feedback by Commenting below 💬

Drop me a Follow for more Awesome content related to Web Development and Programming 🙌

Thank you for your support ❤️

. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .