Phần giữ chỗ

Đôi khi, việc tạo phần giữ chỗ cho nội dung trang có thể đơn giản như việc thêm hiệu ứng nền vào các phần tử trang hiện có. Trong ví dụ này, tất cả các mục danh sách đều có cùng một cấu trúc HTML cơ bản. Tuy nhiên, phần giữ chỗ được tạo kiểu với nền màu xám sử dụng ảnh động CSS để tạo hiệu ứng tải nhấp nháy.

Tuỳ thuộc vào cách triển khai các phần tử trang, bạn cũng có thể cần điều chỉnh CSS một chút để đảm bảo rằng các phần giữ chỗ vẫn chiếm không gian mặc dù không chứa nội dung. Thông thường, bạn có thể thêm thuộc tính width hoặc height vào các phần tử trang hiện có. Ví dụ: trong ví dụ này, việc thêm height: 1.5em vào .text-container đảm bảo phần giữ chỗ của nó vẫn hiển thị mặc dù không chứa bất kỳ văn bản nào.

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: "https://web-dev.imgix.net/image/j2RDdG43oidUy6AL6LovThjeX9c2/GMPpoERpp9aM5Rihk5F2.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;
    }
});