Image Grid Skeleton
Grille 2 × 2 de 260 × 260 px : quatre plages 125 × 125 px, arrondi 12 px, shimmer ease-in-out de 1,8 s sur ::after. Cascade 0 / 0,15 / 0,30 / 0,45 s portée par la propriété personnalisée --skel-delay, posée sur chaque cellule et héritée par le pseudo-élément — les quatre tuiles s'allument l'une après l'autre.
Vous aurez accès à la démo interactive avec un compte gratuit.
Cet effet fait partie d'Effect.Labs — 811 effets vanilla, une partie gratuite, une partie premium. Chargement comprend 29 effets, dont 4 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Structure. .grid-skel est une grille CSS deux colonnes (grid-template-columns: 1fr 1fr, gap: 10px, width: 260px) : les quatre cellules font donc (260 − 10) ÷ 2 = 125 px de large chacune. Leur hauteur est dictée par aspect-ratio: 1/1 → 125 × 125 px. La grille mesure 260 × 260 px au total. Chaque cellule est un div.skel-bone.grid-skel-img : fond rgba(255,255,255,.08), border-radius: 12px (qui écrase les 6 px de la classe parente), position: relative et overflow: hidden pour contenir le pseudo-élément. Aucun JS : l'effet est entièrement CSS.
Shimmer. L'animation repose sur ::after (absolu, inset: 0, content: ""). Son fond est un linear-gradient(90deg, transparent 0, rgba(255,255,255,.1) 50%, transparent 100%) déclaré avec background-size: 200% 100% — le dégradé est deux fois plus large que la cellule. L'@keyframe shimmerSlide déplace la background-position de -200% 0 à 200% 0 : la bande lumineuse entre par la gauche, traverse la cellule et ressort par la droite. Durée : 1,8 s ease-in-out, infini. Le pic de lumière à 10 % d'opacité reste sobre sur le fond gris à 8 %.
Cascade — et pourquoi elle passe par une propriété personnalisée. Le HTML livré porte style="--skel-delay: .15s", .3s et .45s sur trois des quatre cellules (la première n'a pas d'attribut), et .skel-bone::after déclare animation-delay: var(--skel-delay, 0s). Ce détour est nécessaire : l'animation vit sur le pseudo-élément, or un animation-delay posé sur un élément ne se propage pas à son ::after — les propriétés d'animation ne sont pas héritées, chaque pseudo-élément a les siennes. Une propriété CSS personnalisée, elle, est héritée par les pseudo-éléments : var(--skel-delay, 0s) lit la valeur inscrite sur la cellule parente et retombe sur 0s quand rien n'est posé. Mesuré avec l'API getAnimations() : les quatre pseudo-éléments rapportent delay = 0 / 150 / 300 / 450 ms et quatre background-position distinctes au même instant — la cascade est bien visible. Contre-épreuve : un style="animation-delay: .15s" écrit directement sur la cellule laisse les quatre ::after à delay=0ms et à la même position — synchronie parfaite, cascade absente.
Accessibilité
- prefers-reduced-motion absent du code. Confirmé : aucune règle
@media (prefers-reduced-motion: reduce)dans le CSS vendu. Les quatre shimmers tournent en continu quelle que soit la préférence système. Ajoutez@media (prefers-reduced-motion: reduce) { .skel-bone::after { animation: none } }— la plage grise reste visible et signale toujours le chargement, sans mouvement. - Un skeleton screen est un indicateur de chargement fonctionnel, pas un élément purement décoratif. Le conteneur
.grid-skeldevrait porterrole="status"etaria-label="Chargement des images…"pour qu'un lecteur d'écran annonce l'état d'attente. Retirez ces attributs et remplacez-les pararia-hidden="true"une fois le contenu réel inséré. - Les cellules sont des
divvides : aucun texte, aucune icône. Posezaria-hidden="true"sur chaque.skel-bonepour que l'arbre d'accessibilité ne contienne que l'annonce du conteneur. - Intégration. La grille a une
widthfixe (260 px) : sur mobile étroit, ajoutezmax-width: 100%sur.grid-skeletgrid-template-columns: 1fr 1frs'adaptera automatiquement viaaspect-ratio: 1/1.
Compatibilité navigateur
CSS pur, zéro JS. Requiert CSS Grid (2019), aspect-ratio (2021), inset (2021), les propriétés personnalisées var() (2017) et @keyframes/animation (2012).
Sans aspect-ratio (Safari 14 et antérieurs) : les cellules s'aplatissent à hauteur 0 et deviennent invisibles. Repli : ajouter height: 125px sur .grid-skel-img. Sans inset : remplacer par top:0;right:0;bottom:0;left:0 sur .skel-bone::after.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="grid-skel">
<div class="skel-bone grid-skel-img"></div>
<div class="skel-bone grid-skel-img" style="--skel-delay: .15s"></div>
<div class="skel-bone grid-skel-img" style="--skel-delay: .3s"></div>
<div class="skel-bone grid-skel-img" style="--skel-delay: .45s"></div>
</div>
HTML + CSS + JS complet, prêt à coller — avec des centaines d'effets premium.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Durée du shimmer (CSS — .skel-bone::after { animation: 1.8s ease-in-out infinite … shimmerSlide }) |
1,8 s | Vitesse de passage de la bande lumineuse. 1 s = shimmer vif ; 2,5 s = ondulation lente et discrète. |
Largeur de la grille (CSS — .grid-skel { width: 260px }) |
260 px | Détermine la taille des cellules : (largeur − gap) ÷ 2. 200px → ~95 × 95 px ; 340px → ~165 × 165 px. Ajoutez max-width: 100% pour les mises en page fluides. |
Goutière (CSS — .grid-skel { gap: 10px }) |
10 px | Espace entre les quatre cellules. 6 px pour resserrer ; 16 px pour un espacement carte. |
Arrondi (CSS — .grid-skel-img { border-radius: 12px }) |
12 px | 12 px pour des coins légèrement doux. 0 pour des carrés nets (photos plein format) ; 50% pour des cercles (avatars 4 en grille). |
Fond des plages (CSS — .skel-bone { background: rgba(255,255,255,.08) }) |
rgba(255,255,255,.08) | Fond visible au repos et entre les passages du shimmer. Sur un fond clair, passer à rgba(0,0,0,.08). |
Intensité du shimmer (CSS — rgba(255,255,255,.1) dans le dégradé de .skel-bone::after) |
rgba(255,255,255,.1) | .06 = très discret ; .18 = bande nettement visible. Gardez un rapport ≥ 2:1 avec la valeur du fond. |
Cascade (HTML — style="--skel-delay: .15s" sur chaque cellule, lu par .skel-bone::after { animation-delay: var(--skel-delay, 0s) }) |
0 / 0,15 / 0,30 / 0,45 s (la première cellule n'a pas d'attribut : repli 0s) |
Écart entre l'allumage des cellules. Retirer les attributs → shimmer synchrone ; .25s, .5s, .75s → cascade plus marquée. Passez toujours par la propriété personnalisée : un animation-delay écrit directement sur la cellule ne se propage pas à ::after, alors qu'une propriété personnalisée en est héritée. |
FAQ
shimmerSlide est déclarée sur ::after, et qu'un pseudo-élément a ses propres propriétés d'animation : un animation-delay posé sur la cellule parente ne lui est pas transmis — les propriétés animation-* ne sont pas héritées. Les propriétés CSS personnalisées, elles, le sont : .skel-bone::after { animation-delay: var(--skel-delay, 0s) } lit donc la valeur inscrite dans style="--skel-delay: .15s" sur la cellule, et retombe sur 0s pour la première, qui n'a pas d'attribut. Contre-épreuve avec getAnimations() : avec style="animation-delay: .15s" sur la cellule à la place, les quatre pseudo-éléments restent à delay=0ms et brillent en parfaite synchronie. Si vous générez la grille en boucle, écrivez style="--skel-delay: …" sur chaque cellule avec une valeur croissante..skel-bone.grid-skel-img (9 au total) et passez grid-template-columns à 1fr 1fr 1fr. Pour une 4 × 2, ajoutez 4 éléments et passez à 1fr 1fr 1fr 1fr. Ajustez width en conséquence — ex. 370px pour 4 colonnes à ~85px avec gap de 10px. aspect-ratio: 1/1 adapte automatiquement la hauteur. Prolongez la cascade en posant --skel-delay en croissant sur les nouvelles cellules (.6s, .75s…), ou retirez les attributs pour un shimmer synchrone.