Chargement✨ Premium

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.

CSSLoop

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

Virement entre deux comptes — les deux anneaux relient le compte débité au compte crédité — Infinity Loop exemple 1

① Virement entre deux comptes — les deux anneaux relient le compte débité au compte crédité

QuandL'écran de confirmation d'une application bancaire, entre le moment où l'utilisateur valide un virement et celui où la banque confirme le crédit : le compte débité à gauche, le compte crédité à droite, l'opération entre les deux.
PourquoiUn virement, ce sont deux comptes et un mouvement de l'un vers l'autre — exactement ce que dessinent les deux anneaux : un devant chaque compte, qui se rapprochent jusqu'à se chevaucher de 21 px au centre puis s'écartent. La scène montre l'opération elle-même, pas seulement « ça travaille » : un spinner ou une barre de progression ne dit pas entre qui ça se passe. À 1,5× la taille vendue (bloc 120 × 60 px, anneaux 45 px), le bloc remplit exactement l'écart entre les deux cartes et les anneaux se lisent comme deux entités distinctes — réduit dans un bouton, le même effet redevient un point.
Réglageswidth: 120px; height: 60px sur .loader-infinity, anneaux 45 × 45 px, border-width: 6px, translateX(30px) / translateX(-30px) dans les deux keyframes — ×1,5 des 80 × 40 / 30 px / 4 px / 20 px vendus, chevauchement de 21 px à mi-cycle. top: calc(50% - 22.5px) pour centrer, couleur #6366f1, scale(.8) et cycle de 2 s inchangés.
Conversion d'une vidéo MOV → MP4 — la boucle relie le format d'entrée au format de sortie — Infinity Loop exemple 2

② Conversion d'une vidéo MOV → MP4 — la boucle relie le format d'entrée au format de sortie

QuandLa fenêtre de conversion d'un outil vidéo ou bureautique pendant l'encodage : le fichier source et son format d'un côté, le fichier de sortie et son format de l'autre, la transformation entre les deux — souvent plusieurs minutes.
PourquoiUne conversion a une entrée et une sortie qui ne se touchent que le temps de l'opération : l'anneau gauche porte la couleur du badge MOV, l'anneau droit celle du badge MP4, et leur chevauchement à mi-cycle est le moment où l'un devient l'autre. La barre de progression en dessous dit combien il reste ; seule la boucle dit d'où vers où. Le cycle de 2 s reste calme sur un encodage long, là où un spinner rapide finit par suggérer un blocage. À 2× la taille vendue (bloc 160 × 80 px, anneaux 60 px), la forme tient face à deux tuiles de fichier de 140 px sans les écraser.
Réglageswidth: 160px; height: 80px, anneaux 60 × 60 px, border-width: 8px, translateX(40px) / translateX(-40px) — ×2 des valeurs vendues, chevauchement de 28 px à mi-cycle. top: calc(50% - 30px), scale(.8) et cycle de 2 s inchangés. Une couleur par anneau : ::before en #cbd5e1 (badge MOV), ::after en #22d3ee (badge MP4) — deux border-color au lieu d'une.
Synchronisation en cours — tableau de bord d'import — Infinity Loop exemple 3

③ Synchronisation en cours — tableau de bord d'import

QuandUne page de configuration ou un tableau de bord affiche le statut d'une synchronisation active entre deux sources (client / serveur, local / distant, import / export).
PourquoiDeux cercles se rapprochant l'un de l'autre illustrent directement le concept de « deux entités qui se rejoignent ». Un spinner n'a qu'un seul élément — il ne représente pas la relation entre deux systèmes. Le bloc 80 × 40 px s'insère à côté d'un libellé texte sans déborder d'une ligne de tableau.
Réglageswidth: 60px; height: 30px, cercles 22 × 22 px, couleur adaptée au thème, libellé texte « Synchronisation en cours… » placé à droite du bloc.

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-infinity est un div muet, sans role ni contenu textuel. Pour un indicateur de chargement actif, posez role="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, ajoutez aria-hidden="true" à .loader-infinity lui-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 #6366f1 est visible. Sur le fond sombre #0a0a0f du 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.

Chrome 43+✓ Complet
Firefox 16+✓ Complet
Safari 9+✓ Complet
Edge 79+✓ Complet
Mobile iOS 9+✓ Complet
Android Chrome✓ Complet

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) :

index.html — structure
<div class="loader-infinity"></div>
🔒 Débloquer le code complet — à partir de 2,99 € le 1er mois

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éfautEffet
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

Non. Les deux cercles bougent horizontalement au même niveau (même 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.
Spinner (fx-0421) : un seul élément qui tourne à 360° — mouvement rotatif, un seul acteur. Gradient Ring (fx-0435) : un seul anneau à dégradé conique qui tourne — même mécanique de rotation, palette différente. Infinity Loop (fx-0437) : deux éléments distincts en mouvement relatif l'un vers l'autre — aucune rotation, aucun dégradé. C'est la seule entrée de la catégorie Chargement dont l'animation dépend de la relation spatiale entre deux composants séparés.
Le code vendu ne déclare pas de valeur 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.