Gradient Border Animated
Un anneau de 2 px en dégradé conique rose → orange → turquoise dont l'angle de départ est animé de 0 à 360° en 3 s. Une condition souvent oubliée : la déclaration @property qui rend la variable --angle animable — sans elle, l'anneau est immobile.
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. Boutons comprend 27 effets, dont 2 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Trois calques, comme Rotating Border : le bouton .btn-gradient-border-anim (background: #0a0a0f, position: relative; z-index: 1, overflow: hidden; border-radius: 12px via .demo-btn), un ::before à z-index: -2 qui porte le dégradé (inset: -3px; border-radius: 15px) et un ::after à z-index: -1 qui redessine la face (inset: 2px; background: #0a0a0f; border-radius: 10px). L'écart de 2 px entre le bord du bouton et la face est l'anneau visible.
La différence avec Rotating Border est dans ce qui tourne. Ici la boîte ne bouge pas : le dégradé est conic-gradient(from var(--angle, 0deg), #ff0080, #ff8c00, #40e0d0, #ff0080) et l'animation rotateGradientAnim (3s linear infinite) fait varier --angle de 0deg à 360deg. Comme le ::before recouvre toujours tout le bouton, l'anneau devrait rester continu à tout instant — c'est le bon principe, celui qui évite les trous sur les flancs.
Mais une propriété personnalisée n'est interpolable que si elle est enregistrée avec @property. Sans cette déclaration, --angle est une chaîne pour le navigateur, qui l'anime de façon discrète — 0deg pendant la première moitié du cycle, 360deg pendant la seconde. Or 0° et 360° dessinent le même dégradé. Mesuré dans Chromium avec le CSS seul : --angle vaut 0deg à 0, 375, 750 et 1 125 ms, 360deg à 1 500 ms, et les pixels de l'anneau sont identiques à tous ces instants — le bouton est statique. C'est le symptôme d'un @property oublié.
La règle indispensable — @property --angle { syntax: '<angle>'; inherits: false; initial-value: 0deg }, une fois dans la feuille de style — fait tout basculer : l'angle passe par 45° à 375 ms et 90° à 750 ms, les couleurs défilent le long de l'anneau et le dégradé fait un tour complet toutes les 3 s, sans jamais rompre. Vérifiez qu'elle accompagne bien le CSS que vous collez. Aucune règle :hover ni :active : l'animation tourne en permanence.
Accessibilité
- Contraste du texte : blanc sur
#0a0a0f= 19,8:1, niveau AAA. La face est opaque : la couleur de page derrière ne change rien. - Contraste de l'anneau (WCAG 1.4.11, seuil 3:1 pour le contour d'un composant) : sur
#0a0a0f,#ff0080= 5,2:1,#ff8c00= 8,5:1,#40e0d0= 12:1 — le contour de 2 px est perceptible à tout instant du cycle, et il est continu, contrairement à Rotating Border. - prefers-reduced-motion absent du code : le dégradé tourne en permanence. Ajoutez
@media (prefers-reduced-motion: reduce) { .btn-gradient-border-anim::before { animation: none } }— l'anneau reste, figé à 0°, complet et lisible. - Lecteurs d'écran : les deux pseudo-éléments ont
content: "", rien n'est annoncé, le nom accessible est le libellé. Le bouton reste un<button>natif ; l'animation ne dépend pas du survol. - Focus :
outlinen'est pas touché, l'anneau de focus natif reste visible et n'est pas rogné paroverflow: hidden. Cible ≈ 54 px de haut (padding 18 px + texte), au-dessus du minimum de 44 px.
Compatibilité navigateur
Requiert @property, conic-gradient() avec from var(), la propriété raccourcie inset et l'animation d'une propriété personnalisée. Aucun JavaScript, zéro dépendance.
Sans @property — Firefox avant 128, Safari avant 16.4, ou si la règle a été omise — l'anneau dégradé est présent mais immobile : un bouton à bordure conique fixe, lisible et complet. Sans inset (Safari avant 14.1, Firefox avant 66), les pseudo-éléments n'ont ni taille ni position et il ne reste que le texte blanc sur la face.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
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 |
|---|---|---|
| @property --angle (CSS — indispensable, une fois par feuille) | type angle, valeur initiale 0deg | @property --angle { syntax: '<angle>'; inherits: false; initial-value: 0deg } rend la variable interpolable. Sans elle, aucune rotation. Chrome 85+, Safari 16.4+, Firefox 128+. |
| animation-duration (CSS — ::before, rotateGradientAnim) | 3s | Durée d'un tour complet. 2s = vif ; 8s = lent, presque une respiration. La rotation est continue, contrairement à Rotating Border. |
| conic-gradient(from var(--angle), #ff0080, #ff8c00, #40e0d0, #ff0080) (CSS — ::before) | rose → orange → turquoise → rose | Couleurs de l'anneau. Répétez la première en dernier pour éviter un raccord net. Deux couleurs suffisent pour un anneau bicolore qui tourne. |
| inset (CSS — ::after) | 2px | Épaisseur de l'anneau : l'écart entre le bord du bouton et la face. 1px = filet ; 3px = cadre. Ajustez le border-radius de la face (12 − inset). |
| background (CSS — ::after) | #0a0a0f | Couleur de la face. Identique au fond du catalogue ; sur une autre page, alignez-la sur votre surface ou éclaircissez-la pour un bord propre. |
| border-radius (CSS — .demo-btn 12px / ::before 15px / ::after 10px) | 12 / 15 / 10 px | Arrondi des trois calques. Face = bouton − inset de la face. 999px partout = pilule ; l'anneau reste continu, puisque la boîte ne tourne pas. |
| animation-play-state (CSS — à ajouter) | running | paused au repos et running sous :hover::before pour un anneau immobile qui se met à tourner au survol, sans repartir de zéro. |
FAQ
@property, presque toujours. Le code anime --angle de 0 à 360°, mais une propriété personnalisée non enregistrée n'a pas de type : le navigateur ne peut pas calculer 45° entre les deux et bascule d'une valeur à l'autre à mi-parcours — or 0° et 360° donnent le même dégradé. Vérifiez qu'au début de votre CSS figure bien @property --angle { syntax: '<angle>'; inherits: false; initial-value: 0deg }. La rotation démarre immédiatement, sans autre changement. Si la règle est là et que rien ne bouge, votre navigateur ne connaît pas @property (question suivante).@property, donc --angle reste discret et 0° = 360°. Le bouton est complet et lisible, seule la rotation manque — un repli acceptable. Si la rotation est indispensable sur ces navigateurs, repliez-vous sur la technique de Rotating Border (tourner la boîte du ::before avec transform), en faisant du ::before un carré plus grand que la diagonale pour que l'anneau reste continu.@property. Le compromis universel est un ::before carré (width: 200%; aspect-ratio: 1, centré) tourné par transform : continu partout, mais plus lourd à composer que l'animation d'une variable.