ChargementGratuit

Card Skeleton

Carte squelette en CSS pur : avatar circulaire 48 px, bloc image 120 × 280 px et trois lignes de corps — sept zones animées par un reflet blanc à 10 % d'opacité qui traverse chacune en 1,8 s, sans décalage entre elles.

CSSShimmerCard
Survolez ou cliquez la scène pour interagir

Cet effet est gratuit — la catégorie Chargement en contient 29 au total, dont 4 gratuits. Effect.Labs regroupe 811 effets vanilla. Découvrir la catégorie →

Exemples d'usage

Relais
Pour vous Abonnements
Chargement du fil…

① Fil de publications — articles en chargement initial

QuandUne timeline (blog, réseau social interne, newsletter) charge ses cartes au premier affichage ou à l'ouverture d'une section dont les données viennent d'une API.
PourquoiLa structure avatar + visuel + lignes de texte reproduit exactement la forme d'un post avec photo d'auteur, image d'accroche et extrait — l'œil reconnaît la disposition attendue avant que les données arrivent.
RéglagesEmpilez 2 à 3 instances .card-skel côte à côte (grille CSS, gap: 16px). Réduisez .card-skel-img à 80 px pour une liste verticale à miniature horizontale.
Esquisse
Populaire Récent Suivis
Chargement des créations…
Léa Moreau
Studio Ondine · Pro
Refonte de l'app Nova Bank
Mobile · Fintech · Mode sombre
♥ 1 24818,3 k vues

② Galerie de créations — les shots arrivent un par un

QuandUne galerie type Dribbble ou Behance remplit sa grille au changement d'onglet (Populaire → Récent) ou au défilement : les métadonnées d'un projet arrivent vite, sa vignette haute résolution — souvent plusieurs centaines de Ko — quelques dixièmes de seconde plus tard.
PourquoiL'anatomie de ce squelette est exactement celle d'un shot : avatar du créateur et nom en haut, visuel du projet au centre, titre, tags et compteurs dessous. Les sept zones ont chacune un équivalent réel — l'avatar 48 px devient la photo du créateur, le sous-titre son studio, le bloc devient la vignette, et les trois lignes 100 / 100 / 60 % deviennent le titre, la ligne de tags et la courte ligne de compteurs. Un squelette sans en-tête (fx-0469) laisserait le créateur apparaître d'un coup ; ici, à l'arrivée des données, rien ne bouge d'un pixel.
RéglagesCarte ramenée à 244 px (deux par rangée sur 540 px) avec padding: 14px ; .card-skel-img montée de 120 à 148 px (ratio ≈ 3:2 du visuel) et ses marges à 12 px ; avatar 48 px, lignes 10 px, durée 1,8 s et opacités conservés tels quels.
Témoignages
Ils ont choisi Lumen
★ 4,9/5 · 312 avis vérifiés
Sarah Benali
Fondatrice, Atelier Kumo

« Nos réservations ont doublé en trois mois. Et l'équipe répond en moins d'une heure. »

③ Témoignages clients — avis vidéo en attente sur une page de vente

QuandLa section témoignages d'une page de vente reçoit ses avis d'une plateforme tierce (avis vérifiés) après le premier rendu : photo, nom, vignette vidéo et citation arrivent en un seul lot, quelques centaines de millisecondes après le reste de la page.
PourquoiSur une page de vente, un saut de mise en page juste au-dessus du bouton d'achat coûte des conversions : ce squelette réserve exactement la surface de la carte finale — avatar 48 px, en-tête à deux lignes, bloc 120 px, trois lignes de citation — sans qu'aucune dimension du JSON ait été touchée. L'avatar rond annonce déjà « une personne parle », ce qu'un spinner ne dit pas, et la chute 100 / 100 / 60 % reproduit celle d'une citation de trois lignes. Un loader circulaire au centre de la carte n'aurait ni la forme, ni la promesse.
RéglagesDimensions du JSON conservées (avatar 48 px, .card-skel-img 120 px, lignes 10 px) ; seule la largeur passe de 280 à 244 px avec padding: 16px pour tenir deux cartes par rangée. Le bloc image tient lieu de vignette du témoignage vidéo ; retirez-le pour des avis texte seuls.

Comment ça marche

Le composant repose sur deux classes de base. .skel-bone-circle (l'avatar, 48 × 48 px, border-radius: 50%) et .skel-bone (six surfaces rectangulaires) partagent le même fond gris fantôme rgba(255, 255, 255, 0.08), un position: relative et un overflow: hidden. La carte .card-skel mesure 280 px de contenu intérieur avec 20 px de padding — rendu à 322 px une fois les bordures comptées. La ligne d'en-tête utilise display: flex; gap: 14px : l'avatar occupe 48 px fixes, le div restant (flex: 1, soit 218 px) accueille le titre (14 px de haut, 65 % = 142 px) et le sous-titre (10 px, 45 % = 98 px).

Le reflet est porté par le pseudo-élément ::after de chaque zone. Il est positionné en position: absolute; inset: 0 et porte background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.10) 50%, transparent 100%) / 200% 100%. @keyframes shimmerSlide anime background-position de -200% 0 à 200% 0 en 1,8 s ease-in-out infini. Avec un fond d'image large de 200 % et une formule de position en pourcentage (décalage = p/100 × (W − 2W)), le centre lumineux part de 3 × la largeur de l'élément à droite et finit à 1 × la largeur à gauche — le reflet traverse donc de droite à gauche. Il est visible environ 25 % du cycle (≈ 0,45 s).

Les sept zones scintillent en phase : aucune règle animation-delay n'est présente, toutes partagent le même delay: 0s. Les largeurs des trois lignes de corps sont 100 %, 100 % et 60 % (168 px). La deuxième ligne devrait afficher 92 % d'après la règle .card-skel-line:nth-child(2) du CSS, mais cette règle ne s'applique jamais : les lignes occupent les positions 3, 4 et 5 dans .card-skel (derrière .card-skel-header et .card-skel-img). La règle :last-child à 60 %, elle, s'applique correctement. Le code ne contient aucun JavaScript.

Accessibilité

  • prefers-reduced-motion absent (mesuré) : sous émulation prefers-reduced-motion: reduce avec Playwright, les sept zones continuent d'animer (animationPlayState: running). Ajoutez dans votre feuille : @media (prefers-reduced-motion: reduce) { .skel-bone::after, .skel-bone-circle::after { animation: none; } }.
  • Aucun attribut ARIA n'est présent dans le code livré. Pour signaler un état de chargement : ajoutez role="status" et aria-label="Chargement en cours" sur .card-skel, ou aria-busy="true" sur le conteneur parent jusqu'à ce que le contenu réel soit injecté.
  • Les éléments squelettes sont des div vides — les lecteurs d'écran n'annoncent rien par défaut. Si un role="status" gère l'annonce, ajoutez aria-hidden="true" sur .card-skel pour éviter qu'il soit vocalisé en double.
  • Aucun élément focusable ni interactif : le composant est passif. La navigation clavier n'est pas affectée.

Compatibilité navigateur

Repose sur @keyframes, linear-gradient, background-size, background-position animée, position: relative/absolute, inset et overflow: hidden. Aucune variable CSS du site (var(--…)) — fonctionne sur une page vierge sans contexte externe.

Chrome 87+✓ Complet
Firefox 87+✓ Complet
Safari 14.1+✓ Complet
Edge 87+✓ Complet
Mobile iOS 14.5+✓ Complet
Android Chrome 87+✓ Complet

Sans animation CSS (navigateur très ancien ou accélération matérielle désactivée), les zones s'affichent comme des blocs statiques semi-transparents — la structure de chargement reste compréhensible. La propriété inset requiert Chrome 87 / Firefox 87 / Safari 14.1 ; sur les navigateurs antérieurs, remplacez par top: 0; right: 0; bottom: 0; left: 0.

Le code

Copiez les trois blocs dans votre page. Aucune dépendance.

HTML
<div class="card-skel">
  <div class="card-skel-header">
    <div class="skel-bone-circle card-skel-avatar">
    </div>
    <div style="flex:1">
      <div class="skel-bone card-skel-title">
      </div>
      <div class="skel-bone card-skel-subtitle">
      </div>
    </div>
  </div>
  <div class="skel-bone card-skel-img">
  </div>
  <div class="skel-bone card-skel-line">
  </div>
  <div class="skel-bone card-skel-line">
  </div>
  <div class="skel-bone card-skel-line">
  </div>
</div>
CSS
.skel-bone  {
   background: rgba(255, 255, 255, 0.08);
   border-radius: 6px;
   position: relative;
   overflow: hidden;
   }

.skel-bone-circle  {
   background: rgba(255, 255, 255, 0.08);
   border-radius: 50%;
   position: relative;
   overflow: hidden;
   }

.skel-bone::after, .skel-bone-circle::after  {
   content: "";
   position: absolute;
   inset: 0px;
   background: linear-gradient(90deg, transparent 0%, rgba(255, 255, 255, 0.1) 50%, transparent 100%) 0% 0% / 200% 100%;
   animation: 1.8s ease-in-out 0s infinite normal none running shimmerSlide;
   }

.card-skel  {
   width: 280px;
   padding: 20px;
   background: rgba(255, 255, 255, 0.03);
   border-radius: 16px;
   border: 1px solid rgba(255, 255, 255, 0.06);
   }

.card-skel-header  {
   display: flex;
   align-items: center;
   gap: 14px;
   margin-bottom: 20px;
   }

.card-skel-avatar  {
   width: 48px;
   height: 48px;
   flex-shrink: 0;
   }

.card-skel-title  {
   height: 14px;
   width: 65%;
   margin-bottom: 8px;
   }

.card-skel-subtitle  {
   height: 10px;
   width: 45%;
   }

.card-skel-img  {
   height: 120px;
   width: 100%;
   margin-bottom: 16px;
   border-radius: 10px;
   }

.card-skel-line  {
   height: 10px;
   width: 100%;
   margin-bottom: 10px;
   }

.card-skel-line:nth-child(2)  {
   width: 92%;
   }

.card-skel-line:last-child  {
   width: 60%;
   margin-bottom: 0px;
   }

.toggle-skel-bones .skel-bone-circle, .toggle-skel-bones .skel-bone  {
   }

@keyframes shimmerSlide  {
   
  0%  {
   background-position: -200% 0px;
   }
  100%  {
   background-position: 200% 0px;
   }
}
JavaScript (fx-0439)
// Effet CSS pur — pas de JavaScript nécessaire

Personnaliser

Options passées à l'API ou attributs data-* :

Option / propriétéDéfautEffet
Durée du shimmer (CSS — animation: 1.8s) 1.8s Vitesse du cycle complet. 1,2 s = chargement rapide perçu, 2,5 s = rythme plus posé. La bande lumineuse est visible ≈ 25 % du cycle (0,3 s à 1,2 s, 0,625 s à 2,5 s).
Opacité du reflet (CSS — rgba(255, 255, 255, 0.10)) 0.10 Éclat maximal du gradient au centre. Montez à 0,18–0,22 pour un thème clair ou un fond foncé saturé ; descendez à 0,06 pour un shimmer discret.
Opacité de fond des zones (CSS — rgba(255, 255, 255, 0.08)) 0.08 Teinte du gris fantôme au repos. 0,05 = très discret, 0,12 = zones bien visibles. Remplacez rgba(255,255,255,…) par rgba(0,0,0,…) sur fond clair.
Largeur de la carte (CSS — .card-skel { width: 280px }) 280px Passez à 100% pour une carte responsive. Le shimmer s'adapte automatiquement : les largeurs en % suivent la carte, le gradient en 200 % suit l'élément.
Taille de l'avatar (CSS — .card-skel-avatar { width: 48px; height: 48px }) 48 px Le div flex:1 s'ajuste automatiquement. Pensez à mettre à jour le calcul si vous chiffrez des largeurs de titre en pixels.
Hauteur du bloc image (CSS — .card-skel-img { height: 120px }) 120 px 180 px ≈ ratio 16:9 sur 280 px. Supprimez .card-skel-img du HTML pour une carte sans image. Le border-radius: 10px sur cette zone peut être harmonisé avec votre système de design.
Largeur des lignes de corps 100 % / 100 %* / 60 % La dernière ligne est à 60 % via :last-child. La règle :nth-child(2) à 92 % ne s'applique pas (voir FAQ). Pour une cascade décroissante réelle, ajoutez .card-skel-line:nth-child(4) { width: 92%; }.

FAQ

Quelle différence avec Skeleton Card (fx-0469) qui porte presque le même nom ?

fx-0469 a cinq éléments sans avatar (image + titre + trois lignes), des animation-delay échelonnés (0,1 s / 0,2 s / 0,3 s) et un shimmer de gauche à droite sur 1,5 s ease. fx-0439 a sept éléments avec un avatar circulaire et un sous-titre, tous en phase simultanée, shimmer de droite à gauche sur 1,8 s ease-in-out. Utilisez fx-0439 quand la carte réelle inclut une identité auteur ou un profil ; fx-0469 quand la carte n'a pas d'en-tête.

Pourquoi la deuxième ligne est-elle à 100 % et non à 92 % comme prévu ?

La règle .card-skel-line:nth-child(2) cible le 2ᵉ enfant direct de .card-skel. Or les lignes occupent les positions 3, 4 et 5 (derrière .card-skel-header et .card-skel-img) : la règle ne s'applique jamais. Pour corriger : .card-skel-line:nth-child(4) { width: 92%; }.

Puis-je supprimer le bloc image et garder uniquement l'en-tête avec les lignes ?

Oui — retirez <div class="skel-bone card-skel-img"></div> du HTML. Le CSS s'adapte sans modification : :last-child s'appliquera alors à la troisième ligne, le margin-bottom: 16px de l'image disparaît et la carte se compacte. Aucun JS à modifier.