Creating placeholders for page content can sometimes be as simple as adding a background effect to existing page elements. In this example, all list items share the same underlying HTML structure. However, the placeholders are styled with a gray background that uses a CSS animation to create a pulsing loading effect.
Depending on how your page elements are implemented, you may also need to adjust
your CSS slightly to ensure that the placeholders still take up space even
though they don't contain content. Often this takes the form of adding width
or height
properties to existing page elements. For instance, in this example,
adding height: 1.5em
to .text-container
ensures that its placeholder remains
visible even though it doesn't contain any text.
HTML
<div class="grid">
<div class="item">
<div class="image-container">
<img src="hats.jpg">
</div>
<div class="text-container">Hats</div>
</div>
<div class="item empty">
<div class="image-container">
<img src="">
</div>
<div class="text-container">Watches</div>
</div>
<div class="item empty">
<div class="image-container">
<img src="">
</div>
<div class="text-container"></div>
</div>
<div class="item empty">
<div class="image-container">
<img src="">
</div>
<div class="text-container"></div>
</div>
<div class="item empty">
<div class="image-container">
<img src="">
</div>
<div class="text-container"></div>
</div>
<div class="item empty">
<div class="image-container">
<img src="">
</div>
<div class="text-container"></div>
</div>
</div>
CSS
:root {
--placeholder-primary: #eeeeee;
--placeholder-secondary: #cccccc;
}
.grid {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: center;
gap: 1em;
width: 100%;
max-width: 650px;
margin: 1em 0;
}
.item {
display: grid;
gap: .5em;
width: 200px;
}
.text-container {
font-size: 1em;
height: 1.5em;
text-align: center;
font-weight: bold;
}
.image-container {
width: 200px;
height: 200px;;
animation: placeholder ease-in-out 2s infinite;
}
.image-container img {
width: 100%;
}
@keyframes placeholder {
0% {
background-color: var(--placeholder-primary);
}
50% {
background-color: var(--placeholder-secondary);
}
100% {
background-color: var(--placeholder-primary);
}
}
@keyframes fadeIn {
0% {
opacity: 0%;
}
100% {
opacity: 100%;
}
}
.item.loaded .image-container {
animation: none;
}
.item.loaded .image-container img{
animation: fadeIn linear .5s;
}
JS
const data = [
{
description: "Watches",
src: "watches.jpg"
},
{
description: "Shirt",
src: "shirt.jpg"
},
{
description: "Shorts",
src: "shorts.jpg"
},
{
description: "Sunglasses",
src: "sunglasses.jpg"
},
{
description: "Shoes",
src: "shoes.jpg"
}
];
document.querySelectorAll(".item.empty").forEach((el, index) => {
if (data[index]) {
el.classList = "item loaded";
el.querySelector("img").src = data[index].src;
el.querySelector(".text-container").innerHTML = data[index].description;
}
});