Placeholders
Les placeholders sont des blocs gris qui occupent la place du contenu pendant son chargement. Ils évitent que la page « saute » à l’arrivée des données et rassurent sur le fait que le contenu arrive.
Exemple de base#
Une carte avec ses futurs titre, texte et bouton remplacés par des .placeholder. Largeur et hauteur suivent le contenu qu’ils remplacent ; réglez la largeur avec les classes de colonnes ou w-*.
<div class="card" style="max-width: 20rem;" aria-hidden="true">
<div class="card-body">
<h5 class="card-title placeholder-glow"><span class="placeholder col-6"></span></h5>
<p class="card-text placeholder-glow">
<span class="placeholder col-7"></span>
<span class="placeholder col-4"></span>
<span class="placeholder col-4"></span>
<span class="placeholder col-6"></span>
<span class="placeholder col-8"></span>
</p>
<a class="btn btn-primary disabled placeholder col-6" tabindex="-1" aria-disabled="true"></a>
</div>
</div>Largeur#
Les classes de colonnes (col-*) et les utilitaires de dimensionnement (w-25, w-50…) fixent la largeur. Un style en ligne convient pour une valeur exacte.
<span class="placeholder col-6"></span>
<span class="placeholder w-75"></span>
<span class="placeholder" style="width: 25%;"></span>Couleur#
Par défaut un placeholder prend la couleur du texte (currentColor) avec de la transparence. Changez-la avec les classes de fond.
<span class="placeholder col-12"></span>
<span class="placeholder col-12 bg-primary"></span>
<span class="placeholder col-12 bg-secondary"></span>
<span class="placeholder col-12 bg-info"></span>
<span class="placeholder col-12 bg-warning"></span>
<span class="placeholder col-12 bg-danger"></span>
<span class="placeholder col-12 bg-body-secondary"></span>
<span class="placeholder col-12 bg-dark"></span>Taille#
La hauteur dépend de la taille de police. Utilisez .placeholder-lg, .placeholder-sm ou .placeholder-xs pour l’ajuster.
<span class="placeholder col-12 placeholder-lg"></span>
<span class="placeholder col-12"></span>
<span class="placeholder col-12 placeholder-sm"></span>
<span class="placeholder col-12 placeholder-xs"></span>Animation#
.placeholder-glow fait pulser l’opacité des blocs ; .placeholder-wave fait passer une vague de gauche à droite. Placez la classe sur le parent des placeholders.
<p class="placeholder-glow">
<span class="placeholder col-12"></span>
</p>
<p class="placeholder-wave mb-0">
<span class="placeholder col-12"></span>
</p>Squelette d'un relevé#
Combinez les classes pour reproduire la forme d’un contenu réel. L’ensemble est masqué aux lecteurs d’écran et le conteneur est marqué comme occupé.
Chargement des opérations en cours…
<div aria-busy="true">
<p class="visually-hidden" role="status">Chargement des opérations en cours…</p>
<ul class="list-group placeholder-glow" aria-hidden="true">
<li class="list-group-item d-flex justify-content-between">
<span class="placeholder col-5"></span>
<span class="placeholder col-2"></span>
</li>
<li class="list-group-item d-flex justify-content-between">
<span class="placeholder col-4"></span>
<span class="placeholder col-2"></span>
</li>
<li class="list-group-item d-flex justify-content-between">
<span class="placeholder col-6"></span>
<span class="placeholder col-3"></span>
</li>
</ul>
</div>Remplacer le squelette par le contenu#
Retirez aria-busy et remplacez le contenu quand les données arrivent. Le message role="status" peut alors annoncer la fin du chargement.
async function chargerOperations(zone) {
zone.setAttribute('aria-busy', 'true');
const reponse = await fetch('/api/operations');
const operations = await reponse.json();
zone.innerHTML = operations
.map((op) => '<li class="list-group-item">' + op.libelle + ' : ' + op.montant + ' FCFA</li>')
.join('');
zone.removeAttribute('aria-busy');
}Classes
| Classe | Rôle |
|---|---|
.placeholder | Bloc de chargement (affichage en ligne, fond currentColor, opacité .5). |
.placeholder-xs, .placeholder-sm, .placeholder-lg | Hauteurs plus petite ou plus grande que celle de la police. |
.placeholder-glow | Animation de pulsation (sur le parent). |
.placeholder-wave | Animation de vague (sur le parent). |
.col-*, .w-* | Largeur du placeholder. |
.bg-* | Couleur du placeholder. |
Variables Sass
| Variable | Valeur par défaut |
|---|---|
$placeholder-opacity-max | .5 |
$placeholder-opacity-min | .2 |
Personnalisation#
Les deux variables règlent l’opacité de repos et le creux de l’animation .placeholder-glow.
// Sass : placeholders plus discrets
$placeholder-opacity-max: 0.35;
$placeholder-opacity-min: 0.15;
// CSS : placeholder gris bleuté pour une zone précise
.squelette .placeholder {
background-color: #8A9BB5;
border-radius: 0.25rem;
}Bonnes pratiques
À faire
- Reproduisez la forme du contenu final (même nombre de lignes, mêmes largeurs approximatives).
- Marquez le squelette
aria-hidden="true"et ajoutez un texte d’état pour les lecteurs d’écran. - Utilisez
aria-busy="true"sur la zone en cours de chargement, puis retirez-le à l’arrivée du contenu. - Réservez les placeholders aux chargements d’au moins quelques centaines de millisecondes.
À éviter
- N’affichez pas de placeholders sans fin : prévoyez un message d’erreur si le chargement échoue.
- N’utilisez pas à la fois un spinner et un squelette pour la même zone.
- Ne placez pas de texte lisible à l’intérieur des placeholders.
Accessibilité
- Les placeholders sont purement visuels : cachez-les avec
aria-hidden="true"pour que les lecteurs d’écran ne parlent pas de blocs vides. - Un bouton placeholder doit avoir
.disabled,tabindex="-1"etaria-disabled="true"pour ne pas recevoir le focus. - Annoncez le chargement avec un texte
visually-hiddendans un élémentrole="status". - Les animations
placeholder-glowetplaceholder-wavene sont pas coupées automatiquement parprefers-reduced-motion: si votre public le demande, neutralisez-les avec@media (prefers-reduced-motion: reduce) { .placeholder-glow .placeholder, .placeholder-wave { animation: none; } }.