Chargement✨ Premium

Pulse Loading

Sept os — avatar 48 px, bandeau 120 px, trois lignes — pulsent en opacité (1 → 0,4 → 1) en 1,5 s ease-in-out ; décalages 0–400 ms. CSS pur, zéro JavaScript.

CSSPulseCard

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

Fil d'actualité mobile — articles en attente de chargement — Pulse Loading exemple 1

① Fil d'actualité mobile — articles en attente de chargement

QuandÉcran d'une application de lecture (actualités, blog, réseau social) : plusieurs cartes skeleton empilées verticalement occupent le viewport pendant que le serveur répond.
PourquoiLa vague descendante du pulse — chaque os 100 ms après le précédent — donne l'impression d'un contenu qui arrive progressivement plutôt que de clignoter d'un seul bloc. Sur fond sombre, l'absence de shimmer évite les reflets mouvants qui fatiguent l'œil lors d'une consultation nocturne.
RéglagesRépliquez .pulse-skel trois fois avec un gap de 16 px ; pour chaque carte supplémentaire, décalez l'animation-delay global de +200 ms via une variable CSS --card-offset appliquée à chaque os.
Commentaires sous une vidéo en lecture — liste en attente — Pulse Loading exemple 2

② Commentaires sous une vidéo en lecture — liste en attente

QuandPage de lecture vidéo : le lecteur joue déjà (panoramique, 12:47 / 28:10) et, sous lui, la section commentaires affiche des cartes squelettes pleine largeur — avatar 48 px, nom, date, trois lignes — le temps que le fil de commentaires arrive.
PourquoiSous un lecteur en cours de lecture, l'image bouge déjà : un balayage lumineux (fx-0446, fx-0439) ajouterait un second mouvement, directionnel, qui tire l'œil vers la liste au lieu de la vidéo. La pulsation d'opacité n'a pas de trajectoire — chaque os s'assombrit sur place puis revient — et signale l'attente sans concurrencer le lecteur. Côté rendu, seule l'opacité est animée : pas de dégradé à repeindre, pas de pseudo-élément par os ; sur un mobile qui décode déjà la vidéo, les cinq os de chaque commentaire restent une charge négligeable, contrairement au ::after à dégradé mobile des shimmers voisins.
Réglageswidth: 100% et padding: 12px ; .pulse-skel-img supprimé (un commentaire n'a pas de bandeau) ; .pulse-skel-title à 40 % et .pulse-skel-subtitle à 22 % (nom + date) ; marge sous l'en-tête 12 px ; durée 1,5 s conservée ; --card-offset: .2s sur le deuxième commentaire (recette de la FAQ). Sans bandeau, la première ligne devient le deuxième enfant de .pulse-skel et hérite des 90 % du sélecteur nth-child(2) : cascade 90 %/100 %/55 %, crédible pour un texte de commentaire.
Panneau de notifications qui se déroule — rangées en attente — Pulse Loading exemple 3

③ Panneau de notifications qui se déroule — rangées en attente

QuandOutil de travail collaboratif (gestion de projet, suivi de tâches) : l'utilisateur clique sur la cloche, le panneau se déroule sous la barre du haut, en périphérie du tableau qu'il lisait — où un collègue déplace son curseur partagé — et ses rangées — avatar 48 px, titre, horodatage, extrait — respirent le temps de récupérer les notifications.
PourquoiLe panneau s'ouvre dans le champ périphérique, là où la vision est surtout sensible aux mouvements : un reflet qui parcourt une rangée serait perçu même sans regarder le panneau et ferait lever les yeux du tableau. Une variation d'opacité sur place n'a ni direction ni déplacement ; elle indique que les rangées arrivent sans réclamer l'attention. Le rythme de 1,5 s, plus lent que la course d'un balayage, va dans le même sens : le panneau attend, le contenu principal reste le sujet.
Réglageswidth: 100% et padding: 12px 14px ; fond et bordure de carte retirés, séparateur de 1 px entre rangées ; .pulse-skel-img supprimé et une seule .pulse-skel-line (l'extrait, 55 % via :last-child) ; marge sous l'en-tête 12 px ; --row-offset +150 ms par rangée ; durée 1,5 s conservée. Le panneau doit rester plus sombre que la page (ici #0c0c14) pour que des os à 8 % de blanc restent lisibles.

Comment ça marche

Le HTML vendu contient un conteneur .pulse-skel (280 px de large, 296 px de haut, background: rgba(255,255,255,.03), bordure rgba(255,255,255,.06), border-radius: 16px, padding: 20px) avec sept os. L'en-tête (.pulse-skel-header, flex, gap 14 px) aligne le cercle .pulse-skel-avatar (48×48 px) et une colonne flex‑1 contenant .pulse-skel-title (14 px de haut, 65 % de la largeur interne) et .pulse-skel-subtitle (10 px, 45 %). En dessous : .pulse-skel-img (100 % × 120 px, border-radius 10 px) puis trois .pulse-skel-line (10 px de haut : les deux premières à 100 %, la dernière à 55 %). Tous les os partagent background: rgba(255,255,255,.08) et border-radius: 6px (50 % pour le cercle). Le conteneur .demo-preview présent dans le HTML vendu est le cadre de démonstration du site — il n'est pas à inclure dans une intégration.

Un seul @keyframes pulseBreath0 % et 100 % à opacity: 1, 50 % à opacity: 0,4 — s'applique à tous les os : durée 1,5 s, ease-in-out, infini. Les décalages échelonnent le départ : avatar et titre à 0 s, bandeau image à 0,1 s, sous-titre à 0,15 s, puis les trois lignes à 0,2 s / 0,3 s / 0,4 s. L'écart total de 400 ms entre le premier et le dernier os produit une vague descendante de brillance : à t = 750 ms (fond du cycle à 1,5 s), l'image est à opacity ≈ 0,40 tandis que la troisième ligne vient d'atteindre son plein éclat. Aucun JavaScript — le champ js du JSON vendu est vide.

Contrairement aux variantes shimmer de la catégorie — fx-0439 Card Skeleton, fx-0446 Wave Shimmer, fx-0447 Rainbow Shimmer — qui animent la position d'un dégradé sur un pseudo-élément ::after, Pulse Loading n'anime que l'opacité du fond de chaque os : aucun pseudo-élément, aucun dégradé, une seule animation. Un défaut CSS affecte la largeur des lignes : le sélecteur .pulse-skel-line:nth-child(2) ne matche aucun élément — les lignes occupent les positions 3, 4 et 5 parmi les enfants directs de .pulse-skel, pas la position 2 (occupée par .pulse-skel-img). La deuxième ligne s'affiche à 100 % au lieu des 90 % prévus ; la cascade prévue 100 %/90 %/55 % devient 100 %/100 %/55 %, effaçant la décroissance médiane.

Accessibilité

  • prefers-reduced-motion absent du code : pulseBreath s'exécute sans condition, quelle que soit la préférence de l'utilisateur. Ajoutez @media (prefers-reduced-motion: reduce) { .pulse-bone, .pulse-bone-circle { animation: none; opacity: 1; } } pour figer les os au repos.
  • Le conteneur .pulse-skel n'a ni role="status", ni aria-busy="true", ni texte alternatif : les lecteurs d'écran ne perçoivent qu'une zone vide silencieuse. Ajoutez role="status" aria-label="Chargement en cours" sur .pulse-skel et retirez-les quand le contenu réel apparaît.
  • Les sept os sont des div vides sans attribut. Posez aria-hidden="true" sur .pulse-skel (ou sur chaque os) pour éviter une liste de nœuds muets dans l'arbre d'accessibilité — l'information de chargement est alors portée uniquement par le texte alternatif du conteneur.
  • En thème clair, le fond d'os rgba(255,255,255,.08) sur fond blanc devient invisible. Prévoyez une variable CSS — par exemple --pulse-bone-bg — et adaptez sa valeur selon le thème ; rgba(0,0,0,.07) est un bon point de départ pour les fonds clairs.

Compatibilité navigateur

CSS pur (aucun JavaScript) : requiert @keyframes et animation (IE 10+), flex (IE 11 partiel), border-radius et rgba(). Aucun pseudo-élément, aucun dégradé, aucune transformation.

Chrome 21+✓ Complet
Firefox 16+✓ Complet
Safari 9+✓ Complet
Edge 12+✓ Complet
IE 11✓ Complet (flex sans -ms-)
Mobile iOS/Android✓ Complet

Sans CSS animation (IE 9), les sept os s'affichent à opacity: 1 et ne pulsent plus — le squelette reste visible et statique, ce qui reste un repli cohérent pour un indicateur de chargement.

Le code

Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :

index.html — structure
<div class="pulse-skel">
  <div class="pulse-skel-header">
    <div class="pulse-bone-circle pulse-skel-avatar"></div>
    <div style="flex:1">
      <div class="pulse-bone pulse-skel-title"></div>
      <div class="pulse-bone pulse-skel-subtitle"></div>
    </div>
  </div>
  <div class="pulse-bone pulse-skel-img"></div>
  <div class="pulse-bone pulse-skel-line"></div>
  <!-- 2 autres .pulse-skel-line -->
</div>
🔒 Débloquer le code complet — à partir de 2,99 € le 1er mois

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éfautEffet
Couleur des os (CSS — .pulse-bone, .pulse-bone-circle { background }) rgba(255, 255, 255, .08) Luminosité du fond de chaque os au plein éclat. rgba(255,255,255,.12) pour un contraste plus marqué sur fond très sombre ; rgba(0,0,0,.07) pour un thème clair.
Opacité minimale (CSS keyframe — 50% { opacity: .4 }) 0,4 Profondeur du « souffle » : 0 = disparition totale à mi-cycle (clignotement), 0,7 = variation à peine perceptible. Entre 0,3 et 0,5, l'effet ressemble à une respiration ; en dessous de 0,2, il se lit comme un clignotement.
Durée du cycle (CSS — animation: 1.5s …) 1,5 s Vitesse de la respiration. 0,8 s = rapide, sentiment d'urgence ; 2,5 s = lent et doux, adapté aux interfaces de bien-être. Changez la valeur en même temps dans le sélecteur générique et les surcharges de délai.
Décalage maximal (CSS — dernière surcharge animation-delay: .4s) 400 ms (troisième ligne) Amplitude de la vague : 0 ms = tous les os pulsent simultanément ; 800 ms = vague très marquée mais le dernier os est visiblement en retard sur le premier. Redistribuez les délais intermédiaires proportionnellement.
Largeur de la carte (CSS — .pulse-skel { width: 280px }) 280 px Largeur du conteneur. Passez à 100% pour une carte fluide dans une grille ; les os en pourcentage (width: 65%) s'adaptent automatiquement.
Hauteur du bandeau image (CSS — .pulse-skel-img { height: 120px }) 120 px Zone de prévisualisation d'image. 60 px pour un widget de graphique ; 200 px pour un contenu image-first ; supprimez l'élément HTML si votre interface n'a pas de bandeau.
Correction de la deuxième ligne (CSS — .pulse-skel-line:nth-child(2)) 90 % — inactif (selector broken) Le sélecteur actuel ne matche aucun élément : remplacez-le par .pulse-skel > .pulse-skel-line:nth-child(4) (4e enfant de .pulse-skel, soit la 2e ligne) pour retrouver la cascade 100 %/90 %/55 %.

FAQ

Les shimmers animent la position d'un dégradé sur un pseudo-élément ::after : une lumière balaie l'os horizontalement. Pulse Loading anime uniquement l'opacité du fond de l'os lui-même : pas de pseudo-élément, pas de dégradé, pas de mouvement horizontal. Résultat : moins de couches de rendu, code plus court, et un rendu qui ne crée pas de reflet directionnel — adapté aux interfaces où le shimmer mobile paraîtrait trop actif (mode nuit, écrans OLED où les pixels noirs sont éteints).
Le sélecteur .pulse-skel-line:nth-child(2) cible un élément qui est à la fois .pulse-skel-line et le deuxième enfant de son parent. Dans la structure du code vendu, le deuxième enfant direct de .pulse-skel est .pulse-skel-img, pas une ligne : les lignes sont aux positions 3, 4 et 5. Le sélecteur ne matche donc rien et la règle width: 90% n'est jamais appliquée. Correctif : .pulse-skel > .pulse-skel-line:nth-child(4) { width: 90% }.
Répliquez le HTML de .pulse-skel autant de fois que nécessaire et appliquez un décalage de base croissant à chaque carte via une propriété personnalisée. Exemple : .pulse-skel:nth-child(2) { --card-offset: 200ms }, puis sur chaque os animation-delay: calc(var(--delay-bone, 0s) + var(--card-offset, 0s)). La carte 2 démarre 200 ms après la carte 1, produisant une vague entre les cartes en plus de la vague interne à chaque carte.