Un componente de interfaz de usuario de marcador de posición (esquelético) que se muestra hasta que se carga el contenido. Agregar una animación brillante en la que la luz fluye suavemente tiene el efecto de hacer que el tiempo de espera del usuario parezca psicológicamente más corto.

Fue creado asumiendo un diseño tipo tarjeta que se usa con frecuencia en aplicaciones web modernas.

Componente de tarjeta esqueleto

<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>
/* Estilo general de la tarjeta */
.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;
}

/* Compatible con el modo oscuro */
[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;
}

/* Efecto brillo (luz corriente) */
.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%);
  }
}

/* Parte del encabezado (avatar y título) */
.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%;
}