Superellipse Progress Ring
Trois anneaux de progression de 110 px tracés en superellipse : au survol, le tracé passe en 0,8 s d'un rond un peu carré (exposant 2,5) à un carré aux coins doux (exposant 5), comme une icône d'appli, avec une lueur de la couleur de l'anneau — et l'arc garde exactement son pourcentage pendant le changement de forme.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 840 effets vanilla, une partie gratuite, une partie premium. Glassmorphism comprend 47 effets, dont 6 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Chaque .se-progress (110 × 110 px) contient un SVG viewBox="0 0 110 110" tourné de −90° pour que l'arc parte de midi, et deux tracés : la piste .se-bg (trait de 6 px, blanc à 8 %) et l'arc .se-fill (6 px, bouts arrondis, couleur en style). L'arc est un pointillé : stroke-dasharray: var(--dash-total) (320) et stroke-dashoffset: var(--dash-offset). Avec pathLength="320" sur l'arc, la longueur du tracé vaut 320 quelle que soit sa forme : la part remplie est donc (320 − décalage) ÷ 320 — 64 donne 80 %, 176 donne 45 %. Au centre, .se-label affiche la valeur en 20,8 px graisse 800 et un libellé en capitales de 8,8 px à 60 % d'opacité.
La forme vient du JavaScript : superellipsePath(cx, cy, rx, ry, n, segments) calcule 72 segments de la courbe |x|^n + |y|^n = 1. Exposant 2 : un cercle ; 2,5 : un rond légèrement carré (la forme de repos) ; 5 : un carré aux coins très arrondis, proche d'une icône d'appli (la forme au survol). Au chargement, le script pose la forme 2,5 sur chaque anneau ; mouseenter passe à 5, mouseleave revient à 2,5. Le CSS transition: d .8s ease fait le morph : mesuré dans Chromium 151 et Firefox 153, la longueur réelle du tracé passe de 320,7 à 352,5 en 0,8 s (325, 333, 341, 346, 350, 351, 352 par pas de 100 ms), sans saut. Au survol, l'arc reçoit aussi drop-shadow(0 0 6px var(--ring-color)). Changer --dash-offset en JavaScript anime le remplissage en 1 s avec un dépassement d'environ 10 % de la course (cubic-bezier(.34, 1.56, .64, 1) : mesuré, de 64 à 0 le décalage descend à −6 avant de revenir à 0).
Trois réglages tiennent le morph et la valeur justes. La forme de repos est posée par le script dès le chargement, en 72 segments comme la forme de survol : un anneau dessiné en courbes de Bézier ne s'interpolerait pas vers 72 segments droits, et le premier survol sauterait d'un coup (307,8 → 352,5, mesuré), avec un arc qui partirait de 9 h au lieu de midi. pathLength="320" fixe l'échelle du pointillé : les tracés mesurent 307,8 à 352,5 selon la forme, et sans cet attribut l'anneau « 80 % » en montrerait 83 % au repos et 73 % au survol. Aucune animation décorative sur le <svg> : faire varier son border-radius ne changerait rien, il n'a ni fond ni bordure.
Accessibilité
- Lecteurs d'écran : le SVG n'a pas de texte et l'étiquette est un simple
div(« 80% Storage ») : la valeur est lue, mais rien ne dit qu'il s'agit d'une progression. Ajoutez sur.se-progressrole="progressbar",aria-valuenow="80",aria-valuemin="0",aria-valuemax="100"et unaria-label, etaria-hidden="true"sur le SVG. Les scènes de cette page mettent unrole="img"et une phrase complète sur chaque colonne. - Clavier : les anneaux ne sont pas focalisables (mesuré : Tab ne s'y arrête pas) et le morph n'est déclenché que par la souris. Comme il ne porte aucune information — la valeur est la même dans les deux formes —, rien n'est perdu au clavier. Si les anneaux deviennent cliquables, faites-en des liens ou des boutons et appelez le même changement de forme sur
focus/blur. - Contraste : la valeur blanche mesure 19,8:1 sur
#0a0a0fet le libellé à 60 % 7,3:1. Les arcs violet (4,7:1), cyan (8,1:1) et vert (7,8:1) dépassent les 3:1 demandés pour un graphique ; la piste à 8 % (1,2:1) n'est qu'un repère. L'effet est conçu pour un fond sombre : sur fond clair, l'étiquette blanche disparaît — donnez alors--text-primaryfoncé sur.demo-preview. - Mouvement : morph de 0,8 s au survol et remplissage de 1 s quand la valeur change, sans boucle. Pour respecter la préférence :
@media (prefers-reduced-motion: reduce) { .se-progress .se-fill { transition: none } }— la forme et la valeur changent alors d'un coup.
Compatibilité navigateur
SVG, propriété CSS d et sa transition, pathLength, stroke-dasharray/stroke-dashoffset, variables CSS, filter: drop-shadow(). JavaScript : Math.sign, Math.pow, querySelectorAll().forEach, aucune bibliothèque. Mesuré collé dans une page vierge : Chromium 151 et Firefox 153 interpolent le tracé (morph progressif en 0,8 s) ; WebKit 26.5 (Safari) ne connaît pas la propriété CSS d (getComputedStyle(path).d vide) : le tracé change bien de forme au survol, mais d'un coup, sans transition. Dans les trois moteurs, la part remplie reste juste (pathLength) et le remplissage animé fonctionne (même courbe à dépassement, mesurée).
Sans transition de d (Safari, Firefox avant 97), la forme passe directement de 2,5 à 5 : l'anneau reste juste, seul le glissement disparaît. Sans JavaScript, les anneaux restent dessinés par les courbes de Bézier du HTML (forme ronde), arc à la bonne valeur grâce à pathLength, mais sans morph. Pour un morph progressif partout, il faudrait animer l'exposant en JavaScript (requestAnimationFrame, recalcul du tracé à chaque image) au lieu de la transition CSS.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec Premium) :
<div class="demo-preview">
<div class="se-progress-wrap">
<div class="se-progress" style="--ring-color: #8b5cf6; --dash-total: 320; --dash-offset: 64;">
<svg viewBox="0 0 110 110">
<path class="se-bg" d="…"></path>
<path class="se-fill" pathLength="320" style="stroke: #8b5cf6;" d="…"></path>
</svg>
<div class="se-label">80%<small>…</small></div>
</div>
…
</div>
</div>
Le code complet HTML + CSS + JS de Superellipse Progress Ring, prêt à coller — et les 840 effets. Ou 299 € TTC une fois, accès à vie.
Personnaliser
Options passées à l'API ou attributs data-* :
| Option / propriété | Défaut | Effet |
|---|---|---|
Valeur (HTML — --dash-offset dans le style de .se-progress) |
64 · 176 · 96 (80 %, 45 %, 70 %) | --dash-offset = 320 × (1 − part). Modifié en JavaScript (el.style.setProperty('--dash-offset', v)), il anime le remplissage en 1 s avec un léger dépassement. Pensez à changer aussi le texte de .se-label. |
Formes de repos et de survol (JS — les deux morph(2.5) et morph(5)) |
exposant 2,5 au repos, 5 au survol | 2 donne un cercle parfait au repos (contraste maximal avec le survol) ; 4 ou 5 au repos donne des anneaux déjà carrés, comme des icônes. Au-delà de 8, les coins deviennent presque vifs. |
Durée du morph (CSS — transition: … d .8s) |
0,8 s, ease | 0,4 s pour une réponse vive. Sans effet dans Safari, qui n'anime pas la propriété d. |
Couleur (HTML — style="stroke: …" sur l'arc et --ring-color sur .se-progress) |
#8b5cf6 · #06b6d4 · #10b981 | Changez les deux ensemble : --ring-color colore la lueur du survol. Visez 3:1 contre le fond. |
Épaisseur et taille (CSS — stroke-width: 6, .se-progress { width/height: 110px }) |
6 sur 110 px | Le SVG s'adapte à la taille de la boîte ; le trait grossit en proportion. Les tracés sont calculés avec un rayon de 49 dans une boîte de 110 : il reste 6 unités de marge, donc un trait de plus de 12 est rogné par le bord du SVG — réduisez alors le rayon (les deux 49 de l'appel superellipsePath). |
Précision du tracé (JS — 6e argument de superellipsePath) |
72 segments | Les formes de repos et de survol doivent garder le même nombre de segments, sinon la transition redevient sèche. 48 suffit pour 80 px ; 120 pour un anneau de 300 px. |
FAQ
d (le tracé d'un <path>), que Safari ne gère pas : mesuré dans WebKit 26.5, getComputedStyle(path).d est vide et la longueur du tracé passe de 320,7 à 352,5 d'un coup. La forme et la valeur restent justes ; seul le glissement manque. Chrome, Edge et Firefox (depuis la 97) interpolent le tracé. Pour un rendu identique partout, animez l'exposant en JavaScript image par image.pathLength="320" déclare au navigateur que le tracé mesure 320, quelle que soit sa longueur réelle (307,8 à 352,5 selon la forme). Le pointillé de 320 représente donc toujours 100 %, et un décalage de 64 toujours 80 %. Sans cet attribut, l'anneau à 80 % en montrerait 83 % au repos et 73 % au survol.--dash-offset: 320 (anneau vide) dans le HTML, puis posez la vraie valeur après le premier affichage, avec deux requestAnimationFrame imbriqués : requestAnimationFrame(() => requestAnimationFrame(() => el.style.setProperty('--dash-offset', 64))). Avec un seul, Firefox applique directement la valeur finale, sans transition (mesuré). La transition du code vendu (1 s, cubic-bezier(.34, 1.56, .64, 1)) remplit alors l'arc en dépassant d'environ 10 % de la course avant de revenir — mesuré dans les trois moteurs : 320 → 39 → 64.