Skeleton Screen

Written by @phuang 18 November 2022

Skeleton Screen is a visual placeholder that is placed while some heavy networking process is occurring in the background, such as a fetching data. Below is a typical skeleton screen to simulate a comment section fetching data from the server.

Code Snippet:

                                                
                                                <!-- this script is provided by https://www.javascriptfreecode.com coded by: Kerixa Inc. -->
<!DOCTYPE html>
<html lang="en">
<head>

    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Skeleton Screen</title>

<!-- font awesome library include 4.7 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css" integrity="sha512-5A8nwdMOWrSz20fDsjczgUidUBR8liPYU+WymTZP1lmY9G6Oc7HlZv156XqnsgNUzTyMefFTcsFH/tnJE/+xBg==" crossorigin="anonymous" referrerpolicy="no-referrer" />

<!-- css styles -->
<style>
:root{
  margin: 0;
  padding: 0;
  font-family: arial, monospace;
}

html, body{
  height: 100%;
}

body{
  margin: 0 auto;
  padding: 0;
  display: flex;

  justify-content: start;
  align-items: center;
  flex-direction: column;
}

/* card */
.card{
  box-shadow: 0 2px 4px rgb(0 0 0 / 0.1);
  border-radius: 0.25rem;
  width: 300px;
  height: auto;
  margin: 1rem;
  

  display: flex;
  border: 1px solid lightgrey;
}

.card .card__profile{
  padding: 1rem;
  background-color: rgb(245, 245, 245);
  border-top-left-radius: 0.25rem;
  border-bottom-left-radius: 0.25rem;

  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: start;
}

.card .card__content{
  padding: 1rem;
  background-color: white;
  border-top-right-radius: 0.25rem;
  border-bottom-right-radius: 0.25rem;
  width: 100%;
}

.card .card__profile .profile-container{
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background-color: darkgrey;

  display: flex;
  justify-content: center;
  align-items: center;
}

.card .card__profile .profile-container > div{
  color: white;

}

.card .card__content .user{

  font-weight: bolder;
}

.card .card__content hr{
  border: 1px solid rgb(245, 245, 245);
}

.card .card__content .comment{
  font-size: small;
}

/* skeleton card */
.skeleton-card{
  box-shadow: 0 2px 4px rgb(0 0 0 / 0.1);
  border-radius: 0.25rem;
  width: 300px;
  height: auto;
  margin: 1rem;
  

  display: flex;
  border: 1px solid lightgrey;
}

.skeleton-card .card__profile{
  padding: 1rem;
  background-color: rgb(245, 245, 245);
  border-top-left-radius: 0.25rem;
  border-bottom-left-radius: 0.25rem;

  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: start;
}

.skeleton-card .card__content{
  padding: 1rem;
  background-color: white;
  border-top-right-radius: 0.25rem;
  border-bottom-right-radius: 0.25rem;
  width: 100%;
}

.skeleton-card .card__profile .profile-container{
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background-color: lightgrey;

  display: flex;
  justify-content: center;
  align-items: center;
}

.skeleton-card .card__profile .profile-container > div{
  color: white;

}

.skeleton-card .card__content .user > div{
  height: 10px;
  background-color: lightgrey;
  width: 35%;
}

.skeleton-card .card__content hr{
  border: 1px solid rgb(245, 245, 245);
}

.skeleton-card .card__content .comment{
  font-size: small;
}

.skeleton-card .card__content .comment > div{
  margin-bottom: 0.5rem;
}
.skeleton-card .card__content .comment > div:first-child{
  height: 10px;
  background-color: lightgrey;
}

.skeleton-card .card__content .comment > div:nth-child(2){
  height: 10px;
  width: 65%;
  background-color: lightgrey;
}

.skeleton-card .card__content .comment > div:last-child{
  height: 10px;
  width: 80%;
  background-color: lightgrey;
}

.skeleton-card .card__content div{
  border-radius: 0.25rem;
}

.skeleton-animation{
  animation: skeletonLoadAnimate 1.5s ease-in-out;
  animation-direction: alternate;
  animation-iteration-count: infinite;
}
@keyframes skeletonLoadAnimate{

  0%{
    background-color: rgb(235, 235, 235);
  }

  50%{
    background-color: rgb(215, 215, 215);
  }

  100%{
    background-color: rgb(235, 235, 235);
  }
}


section:last-child{
  border: 1px red solid;
  
}

</style>
</head>

<body>

<!-- commments -->
<section>

  <div class="card skeleton-card">

    <div class="card__profile">
    
      <div class="profile-container skeleton-animation">
        <div></div>
      </div>

    </div>

    <div class="card__content">

      <div class="user">
        <div class="skeleton-animation"></div>
        <hr class="skeleton-animation" />
      </div>
    
      <div class="comment">
        <div class="skeleton-animation"></div>
        <div class="skeleton-animation"></div>
        <div class="skeleton-animation"></div>
      </div>
    </div>

  </div>

  <div class="card skeleton-card">

    <div class="card__profile">
    
      <div class="profile-container skeleton-animation">
        <div></div>
      </div>

    </div>

    <div class="card__content">

      <div class="user">
        <div class="skeleton-animation"></div>
        <hr class="skeleton-animation" />
      </div>
    
      <div class="comment">
        <div class="skeleton-animation"></div>
        <div class="skeleton-animation"></div>
        <div class="skeleton-animation"></div>
      </div>
    </div>

  </div>

  
  <div class="card skeleton-card">

    <div class="card__profile">
    
      <div class="profile-container skeleton-animation">
        <div></div>
      </div>

    </div>

    <div class="card__content">

      <div class="user">
        <div class="skeleton-animation"></div>
        <hr class="skeleton-animation" />
      </div>
    
      <div class="comment">
        <div class="skeleton-animation"></div>
        <div class="skeleton-animation"></div>
        <div class="skeleton-animation"></div>
      </div>
    </div>

  </div>
  

</section>

<section>
  <button class="resetTutorial js-reset">Load Comments</button>
</section>


<script>

const comments = [
  {
    username: "eon",
    comments: "There are many variations of passages of Lorem Ipsum available, but the majority have suffered alteration in some form, by injected humour, or randomised words which don't look even slightly believable."
  },
  {
    username: "kerixa",
    comments: "JavaScript is pretty cool!"
  },
  {
    username: "moold",
    comments: "Lorem Ipsum is simply dummy text of the printing and typesetting industry."
  }
]

const cards = document.querySelectorAll(".card");


/*   

Tutorial Description

Skeleton Screen is a visual placeholder that is placed while some heavy networking process is occurring in the background, such as a fetching data. Below is a typical skeleton screen to simulate a comment section fetching data from the server.
*/

// Simulate network fetch that takes 3 seconds
if(document.querySelector(".js-reset") != null){

  document.querySelector(".js-reset").addEventListener("click", event => {
    const button = event.currentTarget;

    if(cards[0].classList.contains("skeleton-card")){
     
      setTimeout( () => {

        setCard(comments);
        button.innerHTML = "Reset Tutorial";
      }, 3000);
    }else{
      addSkeletonScreen(comments);
      button.innerHTML = "Load Comments";
    }


  })
}

function addSkeletonScreen(dataSet){

  let counter = 0;

  dataSet.forEach(data => {

    cards[counter].classList.add("skeleton-card");

    const profile_container = cards[counter].querySelector(".profile-container");
    profile_container.classList.add("skeleton-animation");
    profile_container.querySelector("div").textContent = "";

    const user = cards[counter].querySelector(".user");
    cards[counter].querySelector("hr").classList.add("skeleton-animation");
    user.querySelector("div").classList.add("skeleton-animation");
    user.querySelector("div").textContent = ""

    const comment = cards[counter].querySelector(".comment");
    comment.innerHTML = "";
   
    for(let i = 0; i < 3; i++){

      const div = document.createElement("div");
      div.classList.add("skeleton-animation");
      comment.appendChild(div);
    }

    counter++;
    
  })

}

function setCard(dataSet){

  let counter = 0;

  dataSet.forEach(data => {

    cards[counter].classList.remove("skeleton-card");

    const profile_container = cards[counter].querySelector(".profile-container");
    profile_container.classList.remove("skeleton-animation");
    profile_container.querySelector("div").textContent = data.username.charAt(0).toUpperCase();

    const user = cards[counter].querySelector(".user");
    cards[counter].querySelector("hr").classList.remove("skeleton-animation");
    user.querySelector("div").classList.remove("skeleton-animation");
    user.querySelector("div").textContent = data.username;

    const comment = cards[counter].querySelector(".comment");
    comment.innerHTML = "";
    comment.textContent = data.comments;

    counter++;
    
  })
}



</script>
</body>
</html><a target='_blank' href='https://www.javascriptfreecode.com' style='font-size: 8pt; text-decoration: none'>JavaScript Best Codes</a>                                                
                                            

Example:


About @phuang

Help desk analyst transitioning to a full-stack developer role. Hoping to learn and collaborate with everyone. Happy coding!

P

Comments


Here you can leave us commments. Let us know what you think about this code tutorial!

0 / 300

TRENDING POST
1
2
3
4
5
VISITORS
Online Users: 12
Recent Members: admin_js, bloxio, yqaice, flooketsu, phuang_test
advertisement 2