Bezier Elastic
Au survol, le bouton grossit à 1,08 et monte de 3 px avec une courbe qui dépasse sa cible de 9,8 % avant de s'y poser (pic à 1,088 vers 230 ms) ; au clic il se comprime à 0,95 en 100 ms. Trois états, une transition, aucun JavaScript.
Mis à jour le
Cet effet fait partie d'Effect.Labs — 840 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 états et pas de @keyframes : le repos (dégradé cyan #06b6d4 → #0891b2, texte blanc), le :hover (transform: scale(1.08) translateY(-3px) et box-shadow: 0 15px 35px rgba(6,182,212,.4)) et le :active (transform: scale(.95)). Le mouvement n'est que la transition entre eux : transition: .4s cubic-bezier(.34, 1.56, .64, 1) — toutes propriétés, 400 ms.
La courbe est un « back-out » : son deuxième point de contrôle a une ordonnée de 1,56, au-dessus de 1. La valeur atteint la cible à 37 % du temps (≈ 150 ms), la dépasse de 9,8 % de la distance à 57 % (≈ 230 ms), puis revient s'y poser. Mesuré dans Chromium : l'échelle passe de 1 à un pic de 1,088 à 226 ms, puis 1,08 à 400 ms ; la translation culmine à −3,58 px avant −3,24 px. Deux détails : translateY est écrit après scale, il est donc multiplié par 1,08 — le bouton monte de 3,24 px, pas de 3 ; et l'ombre suit la même courbe, son décalage et son flou dépassent aussi.
Au clic, :active impose transition: .1s : le raccourci remplace toute la transition — 100 ms, courbe ease par défaut, sans dépassement. La pression est un claquement, pas un rebond. La règle omet translateY : le bouton redescend aussi de 3 px. Elle ne touche pas à box-shadow : l'ombre du survol reste sous un bouton pourtant comprimé. Déclaré après :hover, :active l'emporte tant que le bouton de la souris est enfoncé.
Au relâchement, la règle :active disparaît et c'est la transition de l'état survolé qui joue le retour : 400 ms élastiques de 0,95 vers 1,08. Le dépassement étant proportionnel à la distance (0,13 au lieu de 0,08), il est plus visible : pic mesuré à 1,0927 vers 245 ms. C'est le rebond de relâchement, plus que le survol, qui fait l'effet. Quand le curseur quitte le bouton, retour à 1 par la même courbe, avec un creux fugace vers 0,992.
Accessibilité
- Contraste insuffisant : texte blanc sur
#06b6d4= 2,43:1 et sur#0891b2= 3,68:1 — sous le seuil AA de 4,5:1 sur tout le dégradé, et sous 3:1 sur sa moitié claire. Gardez la teinte et assombrissez :#0e7490 → #155e75donne 5,4:1 et 7,3:1. Un texte sombre (#083344) ne suffirait pas : 5,5:1 sur le clair, 3,6:1 sur le foncé. Le grossissement ne change rien au contraste. - prefers-reduced-motion absent du code :
@media (prefers-reduced-motion: reduce) { .btn-bezier-elastic { transition: none } }— les états s'appliquent instantanément. Pour supprimer aussi le mouvement lui-même, ajoutez.btn-bezier-elastic:hover { transform: none }dans la même règle : l'ombre seule signale le survol. - Clavier :
:actives'applique pendant l'appui sur Espace dans la plupart des navigateurs — la compression existe au clavier —, mais aucun:hoverau focus. Ajoutez.btn-bezier-elastic:focus-visible { transform: scale(1.08) translateY(-3px); box-shadow: 0 15px 35px rgba(6,182,212,.4) }. L'outlinenatif est conservé et suit la transformation. - Encombrement : au pic, un bouton de 160 px fait 174 px de large et 55 px de haut, et son ombre s'étend 35 px de flou plus bas. Laissez au moins 8 px de marge entre deux boutons, et un
z-indexau survol si le bouton chevauche un voisin. Cible ≈ 51 px de haut au repos, au-dessus du minimum de 44 px. - Tactile :
:activese déclenche au toucher — la compression est un bon retour mobile ; sur iOS, l'état survolé reste collé après le tap (@media (hover: hover)). Lecteurs d'écran : rien de généré, nom accessible = libellé du<button>natif.
Compatibilité navigateur
Requiert les transitions CSS de transform et box-shadow avec une cubic-bezier() dont les ordonnées sortent de [0, 1] — autorisé par la spécification et pris en charge partout depuis 2012. Aucun JavaScript, zéro dépendance.
Sans transitions, les trois états s'appliquent instantanément : le bouton grossit, se comprime et revient d'un coup — utilisable, sans rebond.
Le code
Structure HTML à coller dans votre page (le CSS + JS sont inclus avec Premium) :
<button class="demo-btn btn-bezier-elastic">Elastic</button>
Le code complet HTML + CSS + JS de Bezier Elastic, 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 |
|---|---|---|
| cubic-bezier(.34, 1.56, .64, 1) (CSS — transition) | dépassement 9,8 % | Le 2ᵉ paramètre règle le rebond : 1.2 ≈ 1 %, 1.4 ≈ 5 %, 1.56 ≈ 10 %, 1.8 ≈ 18 %, 2 = 25 %. Au-delà, le dépassement devient caricatural et l'ombre « saute ». |
| .4s (CSS — transition-duration) | .4s | Durée totale, rebond compris. .25s : vif, le dépassement se sent à peine ; .6s : le bouton flotte. |
| scale(1.08) translateY(-3px) (CSS — :hover) | 1.08 / −3 px | Grossissement et soulèvement. L'ordre compte : translateY après scale est multiplié par l'échelle (3 × 1,08 = 3,24 px). Écrivez translateY(-3px) scale(1.08) pour 3 px exactement. |
| scale(.95) + transition: .1s (CSS — :active) | .95 en 100 ms | Profondeur et vitesse de la pression. scale(.92) : plus marqué ; .15s : plus mou. Ajoutez box-shadow: 0 4px 12px rgba(6,182,212,.3) pour que l'ombre se rapproche avec le bouton au lieu de rester à 15 px. |
| box-shadow: 0 15px 35px rgba(6,182,212,.4) (CSS — :hover) | ombre cyan, 15 px sous le bouton | Ombre colorée de la teinte du dégradé — un halo plus qu'une ombre. rgba(0,0,0,.3) : ombre portée neutre ; 0 8px 20px : plus proche, plus discrète. |
| linear-gradient(135deg, #06b6d4, #0891b2) (CSS — background) | cyan clair → cyan | Pour le contraste AA avec du texte blanc : #0e7490 → #155e75. Changez la couleur de l'ombre en même temps. |
| transition-property (CSS — implicite) | all | Restreignez à transform, box-shadow : un changement de couleur ou de fond (thème, état désactivé) ne rebondira pas avec la même courbe. |
FAQ
transition: .1s est un raccourci : le réécrire remet toutes ses composantes à leur valeur par défaut, donc transition-timing-function: ease. La pression se fait en 100 ms sans dépassement — c'est voulu, un clic doit être sec. Pour une pression élastique, écrivez transition-duration: .1s seul : la courbe du survol est conservée.z-index: 1 sur :hover (le bouton est déjà position: relative) pour qu'il passe au-dessus des éléments suivants, et un conteneur sans overflow: hidden, qui rognerait le dépassement et l'ombre.