Thành phần UI giữ chỗ (khung) được hiển thị cho đến khi nội dung được tải. Việc thêm hoạt ảnh lung linh trong đó ánh sáng chạy mượt mà có tác dụng khiến thời gian chờ đợi của người dùng về mặt tâm lý cảm thấy ngắn hơn.
Nó được tạo ra với bố cục kiểu thẻ thường được sử dụng trong các ứng dụng web hiện đại.
<div class="skeleton-card">
<div class="skeleton-header">
<div class="skeleton-avatar skeleton-shimmer"></div>
<div class="skeleton-title-container">
<div class="skeleton-title skeleton-shimmer"></div>
<div class="skeleton-subtitle skeleton-shimmer"></div>
</div>
</div>
<div class="skeleton-body">
<div class="skeleton-text skeleton-shimmer"></div>
<div class="skeleton-text skeleton-shimmer"></div>
<div class="skeleton-text short skeleton-shimmer"></div>
</div>
</div>
/* Phong cách thẻ tổng thể */
.skeleton-card {
width: 100%;
max-width: 360px;
background: #ffffff;
border-radius: 16px;
padding: 24px;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.05);
display: flex;
flex-direction: column;
gap: 20px;
}
/* Tương thích với chế độ tối */
[data-theme="dark"] .skeleton-card {
background: #1a1a2e;
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.2);
}
/* Skeleton base and animation origin */
.skeleton-shimmer {
background-color: #e0e0e0;
border-radius: 8px;
position: relative;
overflow: hidden;
}
[data-theme="dark"] .skeleton-shimmer {
background-color: #2a2a40;
}
/* Hiệu ứng lung linh (ánh sáng chạy) */
.skeleton-shimmer::after {
content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
transform: translateX(-100%);
background-image: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 0.4) 20%,
rgba(255, 255, 255, 0.6) 60%,
rgba(255, 255, 255, 0)
);
animation: shimmer 2s infinite;
}
[data-theme="dark"] .skeleton-shimmer::after {
background-image: linear-gradient(
90deg,
rgba(255, 255, 255, 0) 0,
rgba(255, 255, 255, 0.05) 20%,
rgba(255, 255, 255, 0.1) 60%,
rgba(255, 255, 255, 0)
);
}
@keyframes shimmer {
100% {
transform: translateX(100%);
}
}
/* Phần tiêu đề (avatar và tiêu đề) */
.skeleton-header {
display: flex;
align-items: center;
gap: 16px;
}
.skeleton-avatar {
width: 48px;
height: 48px;
border-radius: 50%;
flex-shrink: 0;
}
.skeleton-title-container {
flex-grow: 1;
display: flex;
flex-direction: column;
gap: 10px;
}
.skeleton-title {
height: 16px;
width: 60%;
}
.skeleton-subtitle {
height: 12px;
width: 40%;
}
/* Body section (text lines) */
.skeleton-body {
display: flex;
flex-direction: column;
gap: 12px;
}
.skeleton-text {
height: 14px;
width: 100%;
}
.skeleton-text.short {
width: 80%;
}