ChargementGratuit

Classic Spinner

Div 50 × 50 px, radius 50 %, bordure 4 px : côté haut #6366f1 opaque, trois côtés à 20 % — @keyframes spin 1 s linéaire, aucun pseudo-élément, aucun JS.

CSSMinimal
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

Synchronisation de la boîte…
1–50 sur 1 284
Nora LemairePhotos de samedi10:12
ComptabilitéFacture 2026-11809:27
Julien BarbierRelecture avant jeudihier
Théo MarchandPoint hebdo de lundihier
Labo HebdoIdées pour la rentréelun.
Librairie AtlasCommande en routelun.

① Barre d'outils d'une boîte mail — le spinner prend la case de l'icône de synchronisation

QuandClient de messagerie : l'utilisateur relance la réception, ou une synchronisation périodique démarre. Dans la barre d'outils, l'icône de synchronisation cède sa place au spinner, dans la même empreinte de 24 px — et rien d'autre ne bouge : ni libellé, ni voile, ni bandeau.
PourquoiCe spinner n'est qu'une bordure sur un div : ramené à 24 × 24 px en box-sizing: border-box, il occupe exactement la case de l'icône qu'il remplace, sans conteneur ni pseudo-élément à loger dans la barre. L'anneau à 20 % conserve la silhouette pleine de l'icône pendant que l'arc tourne — la barre ne « respire » pas, ce qu'un loader à points ou à barres ne garantit pas puisque sa silhouette change au fil du cycle. Et l'arc qui tourne est déjà le signe de « synchronisation » que tout le monde lit sans légende : c'est ce qui autorise un remplacement muet.
Réglageswidth: 24px; height: 24px; box-sizing: border-box (empreinte exacte de l'icône) et border-width: 3px — un cran au-dessus du ratio de 8 % de la fiche, pour que l'arc reste lisible à cette taille. Durée 1s et couleurs inchangées. Poser role="status" et un libellé masqué sur le bouton hôte, qui garde son fond d'état actif.

② File d'attente d'impression — « Envoi vers Imprimante bureau… » dans une boîte de dialogue système

QuandUne application de bureau (ou le webview d'une app) transmet un document au spooler : une boîte de dialogue système affiche l'imprimante, le document et un bouton Annuler, jusqu'à ce que la file d'attente accuse réception.
PourquoiUne boîte de dialogue système est un registre neutre : le spinner y est attendu, un loader stylisé y jurerait. Cet effet n'a ni dégradé (contrairement à Gradient Ring, fx-0435, dont l'arc s'estompe en conic-gradient), ni lueur, ni changement de couleur — un arc à bord franc sur un anneau discret, en rotation linéaire à 1 s, exactement la grammaire des indicateurs d'activité natifs. Parmi les loaders, c'est celui qui se fond dans l'apparence du système au lieu d'y apposer une signature.
RéglagesRéglages du code conservés : 50 × 50 px, border-width: 4px, 1s linear. Sur le gris du dialogue (#f7f7f9), l'arc #6366f1 mesure 4,2:1 — au-dessus du seuil de 3:1 d'un composant graphique (WCAG 1.4.11) ; l'anneau à 20 % reste perceptible. Le poser en flex: none à gauche du texte, aligné au centre.

Vérification en deux étapes

Code envoyé par SMS au 06 •• •• •• 47

Vérification du code…

③ Vérification d'un code à usage unique (2FA) — spinner sous les 6 cases pendant la validation serveur

QuandÉcran de connexion en deux étapes : la sixième case est remplie, le formulaire s'envoie tout seul. Le spinner apparaît sous le champ le temps que le serveur vérifie le code — de 200 ms à 2 s, sans durée prévisible.
PourquoiLa vérification est courte et binaire : aucune progression à montrer (une barre mentirait), aucune durée à suggérer. Ce spinner tourne en linear infinite avec un seul arrêt de keyframe : il n'a pas de phase privilégiée, donc ni « début » ni « fin » de cycle. Il peut apparaître puis disparaître au bout de 300 ms sans paraître coupé — là où un loader à pulsation (fx-0423, cycles de 2 s) ou à points séquentiels, retiré au milieu de son cycle, semble interrompu. Et le champ reste en place : le spinner occupe la rangée du bouton, pas celle du code.
Réglageswidth: 36px; height: 36px; border-width: 3px (≈ 8 % de la taille, comme le préconise la fiche), 1s conservée. Le centrer dans une rangée de hauteur fixe à la place du bouton (height: 44px; display: flex; align-items: center; justify-content: center) pour que l'apparition puis le retrait ne décalent rien. role="status" et libellé masqué « Vérification du code… ».

Comment ça marche

L'effet est un seul <div class="loader-spinner"> sans enfant ni pseudo-élément. border-radius: 50% sur un carré de 50 × 50 px (zone de contenu, box-sizing: content-box par défaut) trace le cercle ; la bordure de 4 px porte les couleurs. Le boîtier rendu total fait donc 58 × 58 px (50 + 2 × 4). Aucune image, aucun SVG, aucun script exécuté.

L'arc visible émerge de la répartition des opacités sur les quatre côtés. La règle border-color: rgb(99, 102, 241) rgba(99, 102, 241, 0.2) rgba(99, 102, 241, 0.2) utilise la forme à trois valeurs du raccourci (haut / droite+gauche / bas) : le côté haut est pleinement opaque, les trois autres partagent la même teinte à 20 %. L'arc n'est pas découpé ni masqué — seule la différence d'opacité le révèle. La propriété border-image: none est posée explicitement pour neutraliser toute cascade héritée.

@keyframes spin ne contient qu'un seul arrêt : 100% { transform: rotate(360deg) }. L'arrêt 0 % est implicite — le navigateur part de la valeur calculée de l'élément au repos, soit l'identité (rotate(0deg)). La déclaration complète animation: 1s linear 0s infinite normal none running spin fixe : durée 1 s, progression linéaire, délai zéro, boucle infinie. Une révolution par seconde, sans accélération. La clé js du fichier est un commentaire (// Effet CSS pur — pas de JavaScript nécessaire) : rien ne s'exécute.

Accessibilité

  • prefers-reduced-motion absent (mesuré) : sous émulation @media (prefers-reduced-motion: reduce), animationPlayState reste running — la rotation continue à pleine vitesse. Ajouter @media (prefers-reduced-motion: reduce) { .loader-spinner { animation-duration: 8s; } } pour ralentir, ou animation: none si un cercle statique suffit à indiquer l'attente.
  • Aucun attribut ARIA (mesuré) : role, aria-label, aria-live et aria-busy sont tous absents — un lecteur d'écran ignore complètement l'élément. Pour un indicateur de chargement, ajouter role='status' aria-live='polite' et un libellé masqué : <span class='sr-only'>Chargement en cours…</span> à l'intérieur du div.
  • Contraste : l'arc opaque #6366f1 sur fond #0a0a0f donne un rapport de 5,1:1 (WCAG 1.4.11 seuil 3:1, conforme). Sur fond blanc : 4,5:1, conforme également. La partie à 20 % est décorative — aucun critère de contraste ne s'y applique.
  • Pointer events : aucune règle pointer-events: none n'est posée. Si le spinner est superposé à du contenu interactif dans un overlay de chargement bloquant, ajouter pointer-events: none sur le spinner ou cursor: wait sur le conteneur parent.

Compatibilité navigateur

CSS pur : border-radius, border-color avec rgba, @keyframes, animation, transform: rotate(). Aucune variable CSS du design system, aucun JS, aucune dépendance.

Chrome 43+✓ Complet
Firefox 16+✓ Complet
Safari 9+✓ Complet
Edge 13+✓ Complet
IE 11+✓ Complet
Mobile iOS / Android✓ Complet

Sur IE 10, @keyframes et animation nécessitent le préfixe -ms- — sans lui, le div s'affiche comme un cercle statique de 58 px avec l'arc coloré. Sur IE 9 et antérieurs, même résultat statique. La page reste fonctionnelle dans les deux cas.

Le code

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

HTML
<div class="loader-spinner">
</div>
CSS
.loader-spinner  {
   width: 50px;
   height: 50px;
   border-width: 4px;
   border-style: solid;
   border-color: rgb(99, 102, 241) rgba(99, 102, 241, 0.2) rgba(99, 102, 241, 0.2);
   border-image: none;
   border-radius: 50%;
   animation: 1s linear 0s infinite normal none running spin;
   }

@keyframes spin  {
   
  100%  {
   transform: rotate(360deg);
   }
}
JavaScript (fx-0421)
// Effet CSS pur — pas de JavaScript nécessaire

Personnaliser

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

Option / propriétéDéfautEffet
Dimensions (CSS — width et height) 50px Zone de contenu ; boîtier rendu = valeur + 2 × border-width. À 20 px avec bordure 2 px : boîtier total 24 px.
Épaisseur de l'arc (CSS — border-width) 4px Conserver un rapport ≈ 8 % de la taille : 30 px → 2–3 px, 80 px → 6–7 px. Trop fine : arc invisible ; trop épaisse : la surface opaque occupe plus d'un quart du cercle et l'arc disparaît dans une masse.
Couleur de l'arc (CSS — premier terme de border-color) rgb(99, 102, 241) Teinte du côté haut (l'arc visible). Les trois autres côtés utilisent la même teinte réduite à 20 % — changer ce premier terme modifie les quatre côtés à la fois.
Opacité de l'anneau fantôme (CSS — valeur alpha dans rgba) 0.2 0 = trois côtés invisibles, l'arc tourne sur fond nu. 0.5 = anneau bien visible, contraste plus marqué. 1 = disque plein tournant sans arc apparent.
Durée d'une révolution (CSS — 1s dans animation) 1s 0.6 s : rapide, sensation d'urgence. 1.5 s : lent, connoté « traitement long ». Descendre sous 0.4 s : l'arc paraît instable.
Fonction de progression (CSS — linear dans animation) linear ease-in-out crée une illusion de décélération à chaque début de tour ; la rotation paraît vivante mais moins mécanique. linear est le choix standard pour un spinner.
box-sizing (CSS — absent, hérité content-box) content-box (hérité) Ajouter box-sizing: border-box : width: 50px englobe alors la bordure, boîtier rendu = 50 px au lieu de 58 px. Utile pour s'insérer dans un conteneur à largeur fixe.

FAQ

Pourquoi trois valeurs dans border-color plutôt que quatre ?

La propriété border-color avec trois valeurs suit la règle haut / droite+gauche / bas : la deuxième valeur s'applique simultanément aux côtés droit et gauche. Quatre valeurs (rgb(99,102,241) rgba(…) rgba(…) rgba(…)) donneraient le même rendu ; trois termes économisent une répétition. Le côté haut reste seul opaque, les trois autres à 20 %.

Quelle différence avec Gradient Ring (fx-0435) qui trace lui aussi un arc tournant ?

Gradient Ring produit son arc par conic-gradient(transparent, #6366f1) sur le fond du div et creuse le centre via un ::before. L'arc y est dégradé — il s'efface progressivement du transparent vers l'opaque. Classic Spinner n'a aucun pseudo-élément et produit un arc à bord franc par border-color. Si votre composant utilise déjà ::before et ::after pour une icône ou un badge, Classic Spinner s'intègre sans conflit.

Le spinner s'affiche écrasé ou trop grand dans mon composant.

La cause la plus fréquente est l'héritage de box-sizing: border-box d'un framework CSS parent — le boîtier passe de 58 px à 50 px (le cercle reste rond, seulement plus petit). Si le spinner est enfant direct d'un display: flex avec align-items: stretch, il peut s'étirer ; ajouter flex-shrink: 0; align-self: center preserve ses dimensions. Isoler le spinner dans un conteneur neutre (display: flex; align-items: center; justify-content: center) neutralise les deux cas.