Floating Action Labels
Labels CSS purs qui surgissent au survol avec micro-translation — ancrés à leurs boutons d'action, repositionnés automatiquement au scroll, zéro JavaScript.
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. Navigation comprend 36 effets, dont 4 gratuits. Découvrir la catégorie →
3 exemples d'usage



Comment ça marche
Le .floating-label est positionné en position: absolute; top: -36px; left: 50% à l'intérieur du .label-target (position: relative) — il apparaît toujours 36 px au-dessus du bouton, quelle que soit sa position sur la page. Le centrage horizontal repose sur left: 50%; transform: translateX(-50%) : white-space: nowrap garantit que les textes de longueurs variables restent centrés sans calcul JS.
Au survol, deux propriétés CSS transitent simultanément : opacity passe de 0 à 1 et translateY de 6 px à 0 en 0,25 s. Le bouton parent reçoit un transform: scale(1.15) via un cubic-bezier(.34, 1.56, .64, 1) — cette courbe à sur-amortissement produit un léger rebond élastique qui rend le survol plus vivant sans librairie d'animation.
La flèche pointant vers le bouton est un triangle CSS pur : l'élément ::after est placé en top: 100% du label et utilise la technique des borders transparentes (border-color: rgba(15,15,30,.92) transparent transparent) pour former le triangle descendant. Si vous changez la couleur de fond du label, mettez à jour la bordure supérieure du ::after en conséquence.
Le repositionnement au scroll est implicite et ne nécessite aucun JavaScript : .floating-label est en position: absolute dans le flux de .label-target, qui lui-même est dans le flux normal de la page. Le label suit mécaniquement le bouton lors du défilement — contrairement aux tooltips en position: fixed qui nécessitent un getBoundingClientRect() à chaque événement scroll.
Accessibilité
- prefers-reduced-motion absent — le code source ne contient aucun bloc
@media (prefers-reduced-motion). Ajoutez@media (prefers-reduced-motion: reduce) { .floating-label, .label-target { transition: none } }si vos utilisateurs sont sensibles au mouvement. - Accessibilité clavier absente —
:hoverne se déclenche pas à la navigation clavier. Ajoutez.label-target:focus-within .floating-label { opacity: 1; transform: translateX(-50%) translateY(0) }pour la parité clavier/souris. - Contraste label — texte
#e0e7ffsur fondrgba(15, 15, 30, .92): ratio ≈ 9:1, conforme WCAG AA et AAA. - Icônes sans texte — les boutons de la démo ne portent pas d'
aria-label. Ajoutezaria-label="Modifier"(ou équivalent) sur chaque bouton pour les lecteurs d'écran. - Sémantique — remplacez les
<div class="label-target">par des<button type="button" aria-label="…">natifs pour la navigation clavier sans JavaScript supplémentaire.
Compatibilité navigateur
Nécessite CSS position: absolute, opacity et transform — supportés dans tous les navigateurs depuis 2015. Zéro dépendance JavaScript.
Sur mobile et tactile, <code>:hover</code> ne se déclenche pas au tap : les labels restent invisibles. Ajoutez un gestionnaire <code>click</code> ou <code>touchstart</code> qui bascule une classe <code>.label-visible</code> pour pallier l'absence de hover.
Le code
Structure HTML à coller dans votre page (CSS + JS disponibles avec un compte premium) :
<div class="anchor-demo">
<div class="labels-scene">
<button type="button" class="label-target label-target-1" aria-label="Modifier">
<span aria-hidden="true">✎</span>
<span class="floating-label">Modifier</span>
</button>
<button type="button" class="label-target label-target-2" aria-label="Favoris">
<span aria-hidden="true">♥</span>
<span class="floating-label">Favoris</span>
</button>
<button type="button" class="label-target label-target-3" aria-label="Partager">
<span aria-hidden="true">↗</span>
<span class="floating-label">Partager</span>
</button>
</div>
</div>
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 |
|---|---|---|
| top: -36px | -36px | Distance du label au-dessus du bouton (sur .floating-label). Augmentez si le bouton est grand, réduisez pour compacter. Doit rester négatif pour s'afficher au-dessus. |
| translateY(6px) | 6px | Amplitude de la micro-translation à l'entrée du survol. Réduisez à 3 px pour un effet subtil, augmentez à 10 px pour un glissement plus marqué. |
| transition: opacity .25s, transform .25s | .25s | Durée d'apparition/disparition du label. .15s pour une réactivité vive dans un outil productif, .4s pour une UI grand public plus douce. |
| background: rgba(15, 15, 30, .92) | rgba(15,15,30,.92) | Couleur et opacité du fond du label. Adaptez à votre thème — pensez à mettre à jour border-color du ::after en conséquence. |
| border: 1px solid rgba(99, 102, 241, .3) | rgba(99,102,241,.3) | Bordure accent du label. Changez la couleur pour votre teinte brand, ou supprimez-la pour un label sans contour. |
| font-size: .72rem | .72rem | Taille du texte du label. .65rem pour des interfaces denses, .8rem pour plus de lisibilité. |
| transform: scale(1.15) | 1.15 | Facteur d'agrandissement du bouton au survol. scale(1.05) pour la discrétion, scale(1.25) pour plus d'expressivité. |
| cubic-bezier(.34, 1.56, .64, 1) | élastique | Courbe spring du bouton au survol. Remplacez par ease-out pour supprimer le rebond, ou ajustez le 2e paramètre (>1 = sur-amortissement) pour calibrer l'élasticité. |
FAQ
:hover CSS, qui ne se déclenche pas au tap sur iOS et Android. Pour les surfaces tactiles, ajoutez un gestionnaire click ou touchstart qui bascule une classe .label-visible sur le bouton et remplacez .label-target:hover .floating-label par .label-target.label-visible .floating-label..floating-label : pour le bas, passez à top: calc(100% + 8px) et inversez le ::after (border-color: transparent transparent rgba(15,15,30,.92), bottom: 100%). Pour la droite, utilisez left: calc(100% + 8px); top: 50%; transform: translateY(-50%) et adaptez la flèche..floating-label est en position: absolute dans son parent .label-target (flux normal), il suit mécaniquement le bouton lors du défilement. Du JS (getBoundingClientRect, ResizeObserver) n'est nécessaire que si vous basculez en position: fixed pour un tooltip toujours visible à l'écran.