Morph
Au survol, le bouton violet grossit de 10 % et passe de coins à 12 px à une pilule (50 px) en 500 ms sur une courbe à rebond ; sa couleur unie bascule d'un coup vers un dégradé violet → fuchsia — CSS seul, sans état au clic.
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
Deux états seulement : le repos (background: #8b5cf6, border-radius: 12px, scale(1)) et le :hover (border-radius: 50px, transform: scale(1.1), background: linear-gradient(135deg, #8b5cf6, #d946ef)). Aucun @keyframes, aucune règle :active : tout le mouvement est la transition entre ces deux états.
La transition : .5s cubic-bezier(.68, -.55, .265, 1.55) sur toutes les propriétés. Les points de contrôle hors de [0, 1] font sortir la courbe de l'intervalle départ → arrivée. Mesuré dans Chromium sur scale : recul à 0,9925 vers 60–100 ms (le bouton se contracte avant de grossir), dépassement à 1,107 vers 400 ms, puis pose à 1,1 à 500 ms. Le border-radius suit la même courbe : 12 → 50 px avec un pic à ≈ 52,7 px.
Sur un bouton de 50 px de haut, border-radius: 50px vaut une pilule complète (le rayon dépasse la demi-hauteur, le navigateur le plafonne). Le changement de forme et de taille est simultané : c'est cette combinaison, plus que le scale seul, qui donne l'impression que la matière se déforme. Le bouton passe de 113 × 50 px à 124 × 55 px à l'écran sans toucher à la mise en page (transform n'affecte pas les voisins) — il les recouvre de 5 px de chaque côté.
La couleur, elle, ne glisse pas : background-image n'est pas une propriété animable, et le raccourci background du survol remet background-color à transparent. Mesuré à +30 ms : le dégradé est déjà en place. La couleur bascule donc instantanément à l'entrée et à la sortie du survol, pendant que forme et taille rebondissent sur 500 ms — voir la FAQ pour un fondu.
Accessibilité
- Contraste insuffisant dans la version fournie : texte blanc sur
#8b5cf6= 4,23:1, juste sous le seuil AA de 4,5:1 pour un texte de 16 px ; au survol, l'extrémité fuchsia du dégradé (#d946ef) tombe à 3,46:1. Passez à#7c3aedau repos (5,7:1) et àlinear-gradient(135deg, #7c3aed, #c026d3)au survol (5,7:1 → 4,7:1), ou montez le libellé à 18 px gras (seuil 3:1, que l'original respecte). - prefers-reduced-motion absent du code : ajoutez
@media (prefers-reduced-motion: reduce) { .btn-morph { transition: none } }. Forme, taille et couleur changent toujours au survol, mais sans rebond ni glissement. - Clavier : aucun
:hoverà la navigation Tab. Déclarez.btn-morph:focus-visible { border-radius: 50px; transform: scale(1.1); background: linear-gradient(135deg, #8b5cf6, #d946ef) }pour donner au focus le même relief, et gardez l'outlinenatif — le code ne le retire pas. - Lecteurs d'écran : l'effet est purement visuel, le bouton reste un
<button>natif avec son libellé pour nom accessible. Rien à ajouter. - Tactile : sur iOS l'état
:hoverreste collé après un tap — le bouton demeure en pilule agrandie jusqu'au toucher suivant ; enveloppez la règle dans@media (hover: hover). Cible ≈ 50 px de haut (55 px au survol), au-dessus du minimum de 44 px.
Compatibilité navigateur
Requiert les transitions CSS de transform et border-radius avec cubic-bezier() — tous les navigateurs depuis 2012, valeurs de dépassement comprises. Aucun JavaScript, zéro dépendance.
Sans transitions, les deux états s'appliquent instantanément : le bouton saute de sa forme carrée à la pilule agrandie, le dégradé apparaît de la même façon. Aucun navigateur n'anime le passage d'une couleur unie à un dégradé : ce saut de couleur est le comportement normal, pas un repli.
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 |
|---|---|---|
| cubic-bezier(.68, -.55, .265, 1.55) (CSS — transition) | ≈ 0,75 % de recul puis 0,7 % de dépassement sur scale | Ramenez le 2ᵉ et le 4ᵉ paramètre vers 0 et 1 pour calmer le rebond (.68, -.2, .265, 1.2) ; éloignez-les pour l'exagérer. Trop loin, border-radius passe sous 0 un instant : coins carrés. |
| transition-duration (CSS — .btn-morph) | .5s | Durée totale, rebond compris. .3s = réactif (la valeur de Gummy Elastic) ; .8s = gélatineux, à réserver à un gros bouton. |
| scale(1.1) (CSS — :hover) | 1.1 | Grossissement au survol. Sans effet sur la mise en page : le bouton recouvre ses voisins de 5 % de sa largeur de chaque côté. 1.04 dans une barre serrée. |
| border-radius (CSS — 12px repos / 50px survol) | 12 / 50 px | Forme de départ et d'arrivée. 50px = pilule pour tout bouton de moins de 100 px de haut ; 24px = simple arrondi accentué ; 0 au repos = carré qui devient galet. |
| background (CSS — :hover) | linear-gradient(135deg, #8b5cf6, #d946ef) | Couleur du bouton survolé. Bascule sans fondu (non animable). Une couleur unie à la place (#a855f7) redevient animable et glisse avec le reste. |
| background (CSS — .btn-morph) | #8b5cf6 | Couleur au repos. Pour un contraste AA avec le texte blanc : #7c3aed ou plus sombre. |
| transition-property (CSS — implicite) | all | Limitez à transform, border-radius pour que la courbe à rebond ne s'applique pas à une ombre ou une couleur ajoutées plus tard. |
FAQ
linear-gradient, et que background-image n'est pas interpolable — aucun navigateur ne fond une couleur vers un dégradé. Pour un fondu, gardez background: #8b5cf6 sur le bouton, dessinez le dégradé dans un pseudo-élément (::before { inset: 0; background: linear-gradient(…); opacity: 0; transition: opacity .5s; border-radius: inherit }) et passez son opacity à 1 au survol — l'opacité s'anime, et border-radius: inherit lui fait suivre le morphing.:active. Ajoutez-en une après :hover : .btn-morph:active { transform: scale(.96); border-radius: 30px }. Déclarée après, elle l'emporte pendant l'appui, et le relâchement revient à la pilule par la même courbe de 500 ms — c'est exactement la construction de Gummy Elastic, en plus lent.transform ne modifie pas la mise en page : le bouton survolé déborde de 5 % par côté sur ce qui l'entoure, et un voisin peint après lui le recouvre. Donnez au bouton position: relative; z-index: 1 (ou isolation: isolate sur son parent) pour qu'il passe au-dessus, et prévoyez un gap d'au moins 10 % de sa largeur si vous ne voulez aucun chevauchement.