Circular Progress
Arc SVG 60 px, stroke-dashoffset 157→0→−157 en 2 s ease-in-out : l'arc de 4 px s'emplit puis se vide en boucle continue sur une piste à 20 %. Zéro JS.
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
L'effet repose sur un <svg viewBox="0 0 60 60"> de 60×60 px contenant deux <circle> superposés, cx="30" cy="30" r="25". Les deux partagent fill: none, stroke-width: 4 et stroke-linecap: round. Le premier, .bg, reçoit stroke: rgba(99,102,241,.2) — une piste indigo à 20 %. Le second, .progress, reçoit stroke: #6366f1 et le mécanisme d'animation. La circonférence 2π×25 ≈ 157,08 px est arrondie à 157 dans le code.
.progress démarre avec stroke-dasharray: 157 (une seule valeur : tiret et espace valent chacun 157 px) et stroke-dashoffset: 157, ce qui masque entièrement l'arc. L'animation circularProgress — 2s ease-in-out infinite — parcourt trois états : 0 % (offset 157, arc invisible), 50 % (offset 0, cercle complet), 100 % (offset −157, arc invisible à nouveau). De 0 à 50 %, la queue du tiret remonte vers 12 h : l'arc croît dans le sens horaire depuis 12 h. De 50 à 100 %, la tête du tiret progresse dans le sens horaire : l'arc se vide depuis 12 h. Mesuré : offset 156,5 px à t≈50 ms, 7,2 px à t≈1 000 ms (presque plein), −118 px à t≈2 000 ms (vidange aux trois-quarts). La transition 100 %→0 % est imperceptible : offset −157 et offset 157 donnent le même rendu vide.
transform: rotate(-90deg) avec transform-origin: center center décale le point de départ du tracé de 3 h (position SVG par défaut) à 12 h, rendant le chargement naturellement ascendant. L'animation est entièrement CSS — le JS vendu est vide. Les couleurs sont câblées en dur (#6366f1, rgba(99,102,241,.2)) : aucune variable CSS du site n'est requise.
Accessibilité
- prefers-reduced-motion absent : l'animation tourne en boucle infinie quelle que soit la préférence. Ajoutez
@media (prefers-reduced-motion: reduce) { .loader-circular-progress .progress { animation: none } }pour stopper l'arc ; l'arc plein statique (offset 0) est un repli honnête. - L'élément est un
<svg>muet sans rôle ni texte alternatif : aucun lecteur d'écran n'annoncera le chargement. Ajoutezrole="status"sur le<svg>et un<title>caché (Chargement en cours), ou un texte adjacentaria-live="polite"qui annonce la fin de l'opération. aria-busyn'est pas présent sur le conteneur de contenu en cours de chargement. Posezaria-busy="true"sur la zone concernée pendant le chargement et retirez-le à la fin.- Contraste :
#6366f1sur#0a0a0fmesure 3,0:1 (seuil WCAG 1.4.11 pour les éléments graphiques : 3:1) — limite acceptable sur fond sombre, insuffisant sur fond clair (1,9:1 sur blanc). Sur fond clair, portez la couleur à#4f46e5(contraste ≥ 4,5:1).
Compatibilité navigateur
SVG stroke-dashoffset animé en CSS. Aucune dépendance JS, aucune variable CSS externe.
Sans CSS animations (navigateurs très anciens) : arc statique à l'offset initial 157 — invisible. Ajoutez stroke-dashoffset: 0 dans un @supports not (animation-name: x) {} pour afficher un arc plein statique.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<svg class="loader-circular-progress" viewBox="0 0 60 60">
<circle class="bg" cx="30" cy="30" r="25"></circle>
<circle class="progress" cx="30" cy="30" r="25"></circle>
</svg>
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 |
|---|---|---|
Taille (width / height sur .loader-circular-progress) |
60 px | Redimensionne l'ensemble. Si vous changez aussi le rayon r, recalculez stroke-dasharray et les valeurs de l'animation : pour r=12, circonférence ≈ 75, remplacez les trois occurrences de 157 par 75. |
Rayon (attribut r sur les deux <circle>) |
25 | Doit rester inférieur à 30 pour tenir dans le viewBox 60×60 avec le trait de 4 px. Toute modification implique de recalculer stroke-dasharray = 2π×r. |
Épaisseur du trait (stroke-width) |
4 | 2 px pour un rendu fin (mobile, petits espaces) ; 6 px pour un look affirmé. La valeur s'applique aux deux cercles. |
Couleur de progression (stroke: #6366f1 sur .progress) |
#6366f1 | Couleur de l'arc animé. Répercutez la même teinte dans la piste : .bg { stroke: rgba(R,G,B,.2) }. |
Opacité de la piste (.bg { stroke: rgba(99,102,241,.2) }) |
0,2 (20 %) | 0 pour supprimer la piste ; 0,35 pour une piste plus marquée qui renforce la lisibilité sur fond clair. |
Durée du cycle (animation: 2s) |
2 s | 1 s : sensation d'urgence ; 3 s : attente longue et fluide. Modifiez dans la déclaration animation sur .progress. |
Easing (ease-in-out) |
ease-in-out | linear pour une vitesse constante (téléchargement) ; ease-in pour une accélération vers la fin (impression d'aboutissement). |
FAQ
stroke-dashoffset oscille en boucle infinie entre 157 et −157 — il ne reçoit aucune valeur dynamique. Pour un vrai indicateur de 0 à 100 %, supprimez l'animation, ajoutez transition: stroke-dashoffset 0.4s ease et en JS : circle.style.strokeDashoffset = 157 * (1 - progress / 100). À progress = 100, offset = 0 = cercle plein.<div> avec conic-gradient et border-radius: 50% qui tourne en continu — l'anneau est toujours plein, il pivote. Circular Progress est un <svg> dont l'arc se remplit puis se vide via stroke-dashoffset — l'arc croît et disparaît en boucle. Gradient Ring signale une attente indéfinie par rotation ; Circular Progress simule une progression qui recommence, ce qui convient mieux aux opérations courtes répétées (envois, rafraîchissements) et permet d'en faire un vrai barre de progression en retirant simplement l'animation (voir question ci-dessus).stroke-dashoffset = −157 donne le même rendu visuel qu'à 0 % (stroke-dashoffset = 157) : l'arc est invisible dans les deux cas. La transition est donc imperceptible, comme vérifié dans les mesures (offset 156,5 px à t≈50 ms = quasi vide dès le début du cycle suivant).