Boutons✨ Premium

Liquid Fill

Au survol, un remplissage indigo descend du bord supérieur et couvre le bouton en 400 ms pendant que le texte passe au blanc : contour au repos, plein au survol. Un pseudo-élément, une transition, aucun JavaScript.

CSSHoverFill

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

Télécharger — carte d'application de bureau — Liquid Fill exemple 1

① Télécharger — carte d'application de bureau

QuandCarte de téléchargement : icône de l'app, nom, version et poids, un bouton pleine largeur.
PourquoiLe contour au repos dit « disponible », le remplissage qui descend dit « ça arrive » — la métaphore du téléchargement est déjà dans le sens du mouvement livré. Le cas d'usage figurait sur l'ancienne fiche.
RéglagesTexte et bordure #818cf8, remplissage #4f46e5, transition: color .15s .15s, durée .35s.
Envoyer le message — formulaire de contact — Liquid Fill exemple 2

② Envoyer le message — formulaire de contact

QuandFormulaire court : nom, message, un bouton d'envoi aligné sur la largeur des champs.
PourquoiLes champs sont des contours, le bouton aussi : l'ensemble reste léger, et c'est le survol du bouton qui apporte la seule couleur pleine du formulaire, au moment de l'engagement. L'ancienne fiche citait déjà ce cas.
Réglagesbottom: 0 à la place de top: 0 pour un remplissage qui monte, border-radius: 8px, width: 100%.
Charger plus — bas d'une grille de photos — Liquid Fill exemple 3

③ Charger plus — bas d'une grille de photos

QuandGrille de vignettes suivie d'un bouton centré qui charge la page suivante.
PourquoiUn bouton contour n'alourdit pas la grille ; le remplissage vertical évoque la progression d'un chargement — sans promettre plus que ce que le clic fera.
Réglagesheight: 0 → 100% remplacé par width: 0 → 100% avec height: 100% fixe : un balayage horizontal ; padding: 12px 28px.

Comment ça marche

.btn-liquid est un bouton contour : fond transparent, texte et border: 2px solid en #6366f1, et z-index: 1 qui, avec le position: relative de .demo-btn, ouvre un contexte d'empilement. Le remplissage est son ::before : une boîte absolue collée en haut (top: 0; left: 0; width: 100%), de hauteur nulle, fond #6366f1, et z-index: -1 — dans ce contexte, « −1 » la place au-dessus du fond du bouton mais sous son texte.

Au :hover, height passe de 0 à 100% avec transition: height .4s (courbe ease). La boîte étant ancrée par top: 0, elle grandit vers le bas : mesuré dans Chromium, 18 px sur 50 à 86 ms, 36 px à 171 ms, plein à 400 ms. Ce n'est pas un liquide qui monte, malgré le nom — pour qu'il monte, remplacez top: 0 par bottom: 0. Le overflow: hidden et le border-radius: 12px de .demo-btn découpent le remplissage aux angles (rayon intérieur 10 px) : la bordure de 2 px l'encadre proprement.

Le texte passe au blanc par .btn-liquid:hover { color: #fff } — mais aucune transition n'est déclarée sur le bouton lui-même : la couleur bascule à l'instant du survol, alors que le remplissage n'atteint le haut des lettres qu'à ≈ 80 ms et ne les couvre entièrement qu'à ≈ 160 ms. Pendant ce temps, le libellé blanc repose sur le fond de votre page : invisible sur une page claire, sans conséquence sur une page sombre. À la sortie, l'inverse : le texte redevient indigo d'un coup sur un remplissage encore indigo, et disparaît ≈ 80 à 160 ms, le temps que le fond se retire. transition: color .15s .15s sur .btn-liquid supprime les deux artefacts.

À la sortie, height revient à 0 en 400 ms : le remplissage se retire vers le haut, par le bas. Le mouvement anime height, propriété de mise en page recalculée à chaque image ; la version composée (transform: scaleY() avec transform-origin: top) donne le même rendu sans toucher au thread principal (voir Personnaliser). Aucune règle :active : le clic n'ajoute rien.

Accessibilité

  • Contraste insuffisant dans les deux états : au repos, #6366f1 sur #0a0a0f = 4,42:1 ; au survol, blanc sur #6366f1 = 4,47:1 — les deux juste sous le seuil AA de 4,5:1. Sur ce fond, aucune couleur unique ne peut réussir les deux (le produit des deux rapports plafonne à 19,75, il en faudrait 20,25) : séparez-les. Texte et bordure #818cf8 au repos (6,6:1), remplissage #4f46e5 (blanc à 6,3:1). Sur une page blanche, #4f46e5 partout suffit (6,3:1 dans les deux états).
  • prefers-reduced-motion absent du code : @media (prefers-reduced-motion: reduce) { .btn-liquid::before { transition: none } } — le bouton devient plein d'un coup au survol ; l'état reste, seul le mouvement disparaît.
  • Bascule de couleur non synchronisée : le libellé blanc précède le remplissage d'environ 80 ms (voir Comment ça marche). Sur fond clair, c'est un clignotement du texte à chaque survol. Ajoutez transition: color .15s .15s à .btn-liquid pour que la couleur attende le remplissage, dans les deux sens.
  • Clavier : aucun :hover au focus. Doublez les deux règles avec :focus-visible — .btn-liquid:focus-visible { color: #fff } et .btn-liquid:focus-visible::before { height: 100% } — pour que Tab remplisse le bouton comme le survol. Le code ne touche pas outline : l'anneau de focus natif reste, dessiné hors de la boîte et donc non rogné par overflow: hidden.
  • Lecteurs d'écran : content: "", rien n'est annoncé ; <button> natif, nom accessible = libellé. Tactile : le remplissage apparaît au tap et reste (iOS) — @media (hover: hover) pour l'éviter. Cible 54 px de haut (16 + 18 + 16 + 2 × 2), au-dessus du minimum de 44 px.

Compatibilité navigateur

Requiert la transition CSS de height, les pseudo-éléments et un z-index négatif dans un contexte d'empilement — tous les navigateurs depuis 2012. Aucun JavaScript, zéro dépendance.

Chrome 26+✓ Complet
Firefox 16+✓ Complet
Safari 9+✓ Complet
Edge 12+✓ Complet
Mobile iOS✓ Complet (rempli au tap, reste rempli)
Android Chrome✓ Complet (au tap)

Sans transitions, le bouton passe du contour au plein instantanément au survol, et inversement ; l'information est identique, seul le mouvement manque.

Le code

Structure HTML à coller dans votre page (le CSS + JS sont inclus avec Premium) :

index.html — structure
<button class="demo-btn btn-liquid">Liquid Fill</button>
Débloquer le code complet — 9,90 € TTC/mois

Le code complet HTML + CSS + JS de Liquid Fill, 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éfautEffet
top: 0 (CSS — ::before) top: 0 (descend) Ancre du remplissage. bottom: 0 : il monte. top: 50%; transform: translateY(-50%) : il s'ouvre depuis le centre vers les deux bords.
transition: height .4s (CSS — ::before) .4s ease Durée et courbe. .25s : réactif ; cubic-bezier(.2, .8, .2, 1) : départ rapide, arrivée douce, plus « fluide ».
#6366f1 (CSS — color, border, background du ::before) #6366f1 × 3 Trois occurrences. Pour le contraste AA, dissociez-les : #818cf8 texte et bordure, #4f46e5 remplissage (voir Accessibilité).
transition: color (CSS — à ajouter sur .btn-liquid) absente (bascule instantanée) transition: color .15s .15s : le texte change de couleur pendant que le remplissage le recouvre, et non avant. Indispensable sur fond clair.
border: 2px solid (CSS — .btn-liquid) 2px 1px : contour fin ; 0 : le remplissage va jusqu'au bord, avec le rayon complet de 12 px — le bouton n'a plus de forme au repos, prévoyez un fond léger.
transform: scaleY() (CSS — alternative composée) height 0 → 100% Version GPU : ::before { height: 100%; transform: scaleY(0); transform-origin: top; transition: transform .4s } et :hover::before { transform: scaleY(1) }. Même rendu, aucun recalcul de mise en page.
z-index: 1 (CSS — .btn-liquid) et -1 (::before) 1 / -1 À garder tels quels : le z-index: 1 crée le contexte d'empilement qui retient le ::before sous le texte mais au-dessus des fonds de la page. Sans lui, le remplissage passe derrière les conteneurs parents et peut disparaître.

FAQ

En changeant l'ancre : bottom: 0 au lieu de top: 0 sur .btn-liquid::before. La hauteur grandit alors depuis le bord inférieur. Rien d'autre à toucher : la transition, la découpe et la bordure fonctionnent à l'identique.
Parce que la couleur du texte change instantanément alors que le remplissage met 400 ms : à l'entrée, du blanc sur le fond de la page pendant ≈ 80 ms (jusqu'à ce que le remplissage atteigne les lettres) ; à la sortie, de l'indigo sur un remplissage indigo pendant ≈ 80 à 160 ms. Ajoutez transition: color .15s .15s à .btn-liquid : la couleur commence à changer quand le remplissage arrive sur le texte, dans les deux sens.
Oui : le fond du ::before est libre. background: linear-gradient(180deg, #6366f1, #8b5cf6) donne un remplissage dégradé, une image avec background-size: cover fonctionne aussi. Comme la boîte grandit de 0 à 100 % de hauteur, un dégradé s'étire avec elle pendant les 400 ms ; pour qu'il se révèle sans s'étirer, fixez sa taille à celle du bouton — background-size: 100% 50px; background-position: top.