Infinity Loop
Deux cercles de 30 px se rapprochent de 20 px et rétrécissent à 0,8 à mi-cycle — 14 px de chevauchement — puis s'écartent. Bloc 80 × 40 px, 2 s, CSS pur.
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 seul élément HTML : .loader-infinity, un bloc de 80 × 40 px, position: relative. Ses deux pseudo-éléments ::before et ::after forment les deux cercles : 30 × 30 px chacun, border: 4px solid #6366f1, border-radius: 50%, aucun fond. ::before est positionné en left: 0, ::after en right: 0 — leurs bords intérieurs sont séparés de 20 px au repos. Aucun top n'est déclaré : les deux cercles s'appliquent en top: 0, avec 10 px vides en bas du bloc. Aucun JavaScript n'est fourni.
Deux @keyframes symétriques animent chaque cercle sur une période de 2 s, fonction linear, boucle infinie. infinityLeft emmène ::before de translateX(0) scale(1) à translateX(20px) scale(.8) à la moitié du cycle, puis le ramène. infinityRight applique la même mécanique à ::after dans le sens opposé : translateX(-20px) scale(.8). Les deux animations démarrent sans délai et restent synchrones tout au long du cycle. À t = 1 s, les deux cercles mesurent 24 px (30 × 0,8) et se superposent sur 14 px — le centre gauche est à 35 px, le centre droit à 45 px, les rectangles englobants se chevauchent de [30, 44]. À t = 0 s et t = 2 s, les bords intérieurs sont exactement à 20 px de distance.
L'animation ne trace pas la trajectoire en huit du symbole ∞ : les deux cercles bougent horizontalement au même niveau, sans déplacement vertical. Le chevauchement de 14 px à mi-cycle évoque le croisement central du signe infini sans le reproduire géométriquement. L'effet ne contient aucune variable var(--…) : le rendu ne dépend d'aucune propriété du design system hôte. Aucune règle @media (prefers-reduced-motion) n'est présente dans le CSS vendu : mesuré avec émulation Playwright (reducedMotion: 'reduce'), les animations restent à 2s running.
Accessibilité
- prefers-reduced-motion absent du code : avec l'émulation Playwright activée, les animations restent à
2s linear running. Ajoutez :@media (prefers-reduced-motion: reduce) { .loader-infinity::before, .loader-infinity::after { animation: none; } }— les deux cercles restent visibles et fixes, ce qui est un repli honnête pour un indicateur. .loader-infinityest undivmuet, sansroleni contenu textuel. Pour un indicateur de chargement actif, posezrole="status"sur l'élément parent et incluez un texte masqué visuellement :<span class="sr-only">Chargement en cours…</span>. Retirez l'ensemble — ou videz la zone live — dès que l'opération est terminée.- Aucun élément focalisable, aucun événement clavier ni pointeur. L'effet est purement décoratif côté DOM interactif. Si le
role="status"est posé sur un conteneur parent, ajoutezaria-hidden="true"à.loader-infinitylui-même pour éviter qu'un lecteur d'écran ne parcoure ses pseudo-éléments vides. - Contraste : les cercles sont des anneaux ouverts, seule la bordure
#6366f1est visible. Sur le fond sombre#0a0a0fdu code vendu, l'indigo dépasse le seuil de 3:1 requis pour les composants non textuels (WCAG 1.4.11). Sur fond clair ou coloré, vérifiez le ratio avant d'intégrer.
Compatibilité navigateur
CSS pur : @keyframes, transform dans les keyframes, border-radius: 50% et la propriété animation sans préfixe. Aucune variable CSS, aucun JS.
Sans CSS animations (IE 9 et antérieur), les deux cercles s'affichent à leur position initiale, fixes — un double anneau statique. Il n'y a pas de JavaScript à désactiver.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="loader-infinity"></div>
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 |
|---|---|---|
Couleur des cercles (CSS — border: 4px solid #6366f1) |
#6366f1 | Couleur des deux anneaux. currentColor hérite de la couleur du texte parent — utile dans un bouton ou une bulle colorée. La propriété ne s'applique qu'à la bordure, les cercles n'ont pas de fond. |
Épaisseur de la bordure (CSS — border-width: 4px) |
4 px | Épaisseur du trait de l'anneau. 2px donne un filaire fin ; 6px des disques quasi-pleins. Si vous changez la taille des cercles, ajustez l'épaisseur proportionnellement. |
Taille des cercles (CSS — width: 30px; height: 30px) |
30 × 30 px | Diamètre de chaque cercle. Si vous augmentez, vérifiez que les deux pseudo-éléments tiennent dans le conteneur — le conteneur fait 80 px de large, les deux cercles occupent 60 px au repos, il reste 20 px de marge centrale. |
Taille du conteneur (CSS — .loader-infinity { width: 80px; height: 40px }) |
80 × 40 px | Emprise totale de l'indicateur. La hauteur devrait être ≥ diamètre des cercles + marge visuelle souhaitée. Ajoutez top: calc(50% - 15px) sur les pseudo-éléments pour les centrer verticalement quand vous changez la hauteur. |
Distance de rapprochement (CSS — translateX(20px) / translateX(-20px)) |
20 px (chevauchement de 14 px à mi-cycle) | Déplacement de chaque cercle vers le centre à mi-période. 10px : les cercles restent séparés (écart de 0 px entre les bords, pas de superposition). 30px : chevauchement total de 30 px, les deux cercles se fondent presque. Modifiez les deux keyframes ensemble. |
Réduction à mi-cycle (CSS — scale(.8)) |
.8 (cercles à 24 px à mi-cycle) | Facteur d'échelle au moment du rapprochement maximal. 1 : pas de changement de taille, seul le translation crée l'effet. .6 : les cercles rétrécissent à 18 px, l'impression de « s'enfoncer » l'un dans l'autre est plus prononcée. |
Durée du cycle (CSS — animation: 2s) |
2 s | Période d'un aller-retour complet. Changez la valeur sur les deux pseudo-éléments simultanément. 1s : animation vive, signale une attente courte ; 3s : rythme lent, adapté à une génération longue. |
FAQ
top: 0) sans aucun déplacement vertical. Ils se superposent sur 14 px à mi-cycle, ce qui évoque le croisement central du signe infini, mais la trajectoire de chaque cercle est une simple oscillation droite-gauche sur 20 px. « Infinity Loop » désigne la répétition infinie du cycle, pas la géométrie du ∞. Pour un vrai dessin en huit, il faudrait ajouter une translation verticale sinusoïdale ou utiliser un offset-path SVG.top sur les pseudo-éléments : ils héritent de top: 0, plaçant les cercles de 30 px en haut du bloc de 40 px — 10 px vides restent en bas. Pour centrer, ajoutez top: 5px (ou top: calc(50% - 15px)) à .loader-infinity::before, .loader-infinity::after.