Build a Pixel Perfect Skeleton Loader Using CSS 🚀
Tags: css, html, javascript, react
Published: 2021-09-15 15:55:52

**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 🖼️

<div align="center">
  <img src="https://i.ibb.co/j54R1gC/Copy-of-Copy-of-Dopefolio-Open-Source-Portfolio-Template-for-Developers-2.gif" alt="Skeleton Loader Preview Demo" width="100%" style="margin: 0;"/>
</div>

---

### 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 ⬇️**

```html
<!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>

```

### **CSS Code ⬇️**

```CSS
      * {
        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;
      }
```

### **Result ⬇️**

<div align="center">
  <img src="https://i.ibb.co/yQwJKPm/Fire-Shot-Capture-078-127-0-0-1.png" alt="Food Blog Result Demo" width="100%" style="margin: 0;"/>
</div>


--- 
## **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.

```html
      <div class="card card--skeleton">
```

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.
```html
    <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>
```

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

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

.card--skeleton .user-avatar-cont {
  background: #eee;
}
```
So the end result will look like this ⬇️

<div align="center">
  <img src="https://i.ibb.co/KqzQCMW/Fire-Shot-Capture-079-127-0-0-1.png" alt="Skeleton Loader Preview Demo" width="100%" style="margin: 0;"/>
</div>

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.


```css
.card--skeleton .user-name span,
.card--skeleton .user-profession span {
  background: #eee;
  color: #eee;
  border-radius: 5px;
}
```

Now, the end result will look like this ⬇️

<div align="center">
  <img src="https://i.ibb.co/Yy1Pqqb/Fire-Shot-Capture-080-127-0-0-1.png" alt="Skeleton Loader Preview Demo" width="100%" style="margin: 0;"/>
</div>

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.

```css
      .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;
      }
```
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 ⬇️

<div align="center">
  <img src="https://i.ibb.co/TLvRkwx/Fire-Shot-Capture-081-127-0-0-1.png" alt="Skeleton Loader Preview Demo" width="100%" style="margin: 0;"/>
</div>

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.

```css
      @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;
      }

```

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

<div align="center">
  <img src="https://i.ibb.co/7g21tVH/ezgif-com-gif-maker-6.gif" alt="Skeleton Loader Preview Demo" width="100%" style="margin: 0;"/>
</div>

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](https://linkedin.com/in/rammcodes)**, **[Twitter Profile](https://twitter.com/rammcodes)**

---

## P.S. ✌️

I recently created one **OpenSource Project** which is a **Portfolio Website Template for Developers** called **[Dopefolio](https://github.com/rammcodes/dopefolio)** and wrote an Article about it on **dev.to**.

Feel free to check the article **[here](https://dev.to/rammcodes/i-created-an-opensource-portfolio-template-for-developers-1ij9)** 😄

---

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** ❤️