Navigation✨ Premium

Floating Action Labels

Pure CSS labels that pop above action buttons on hover with a micro-translation — anchored via normal flow, they reposition on scroll without JavaScript.

CSSHoverPosition

You'll get access to the interactive demo with a free account.

This effect is part of Effect.Labs — 811 vanilla effects, some free, some premium. Navigation has 36 effects, including 4 free. Explore the category →

3 usage examples

WYSIWYG Toolbar — Editing actions revealed on hover — Floating Action Labels example 1

① WYSIWYG Toolbar — Editing actions revealed on hover

WhenIn a content editor (articles, emails, documents) with an icon-only toolbar: labels appear on hover to guide less experienced users without cluttering the resting UI.
WhyThe interface stays clean for experts who recognize the icons; floating labels provide instant contextual help without a slow tooltip. CSS repositioning keeps labels aligned even when the toolbar is sticky.
Settings40×40 px buttons, top: -32px for maximum compactness, transition: opacity .18s for snappy feedback, label background in brand color.
Interactive Map — FAB buttons repositioned on scroll, no JS — Floating Action Labels example 2

② Interactive Map — FAB buttons repositioned on scroll, no JS

WhenIn an interactive map (city plans, POIs, routes) whose FAB buttons — Add a place, Filter, Recenter — are grouped in a screen corner and must stay aligned with their labels as the user scrolls the map.
WhyLabels mechanically follow buttons on scroll through CSS normal-flow positioning — no <code>getBoundingClientRect</code> or scroll listener needed. This is the effect's key differentiator over <code>position: fixed</code> tooltips. In a screen corner, labels are simply repositioned to the left by CSS to avoid overflow — demonstrating the effect's placement flexibility.
Settings48×48 px round buttons, labels repositioned to the side (right: calc(100% + 10px); top: 50%; transform: translateY(-50%)), reversed caret pointing toward the button (border-color: transparent transparent transparent rgba(15,15,30,.92)), scale(1.15) with elastic bounce.
Media player controls — Labels on hover over icons — Floating Action Labels example 3

③ Media player controls — Labels on hover over icons

WhenIn a custom video or audio player whose control bar shows only icons: Play, Volume, Subtitles, Fullscreen.
WhyIcons alone suffice for regular users; floating labels help newcomers identify advanced functions (playback speed, quality) without visually overloading the control bar.
Settingstop: auto; bottom: 44px so labels appear above the control bar (avoids clipping at the bottom of the player), label background at 96% opacity for readability on dark backgrounds.

How it works

The .floating-label is positioned with position: absolute; top: -36px; left: 50% inside the .label-target (position: relative) — it always appears 36 px above the button, regardless of where on the page the button sits. Horizontal centering relies on left: 50%; transform: translateX(-50%) : white-space: nowrap keeps labels of varying lengths centered without any JS measurement.

On hover, two CSS properties transition simultaneously: opacity goes from 0 to 1 and translateY from 6 px to 0 over 0.25 s. The parent button also receives a transform: scale(1.15) via a cubic-bezier(.34, 1.56, .64, 1) — this over-damped curve produces a slight elastic bounce that makes the hover feel lively without any animation library.

The caret pointing toward the button is a pure CSS triangle: the ::after element is placed at top: 100% of the label and uses the transparent-border trick (border-color: rgba(15,15,30,.92) transparent transparent) to form the downward triangle. If you change the label background color, update the top border of ::after accordingly.

Scroll repositioning is implicit and requires no JavaScript: .floating-label is in position: absolute within the flow of .label-target, which itself is in the normal page flow. The label mechanically follows the button on scroll — unlike position: fixed tooltips that need a getBoundingClientRect() on every scroll event.

Accessibility

  • prefers-reduced-motion absent — the source code contains no @media (prefers-reduced-motion) block. Add @media (prefers-reduced-motion: reduce) { .floating-label, .label-target { transition: none } } for motion-sensitive users.
  • Keyboard accessibility absent:hover does not trigger on keyboard navigation. Add .label-target:focus-within .floating-label { opacity: 1; transform: translateX(-50%) translateY(0) } to match keyboard and mouse behavior.
  • Label contrast#e0e7ff text on rgba(15, 15, 30, .92) background: ratio ≈ 9:1, compliant with WCAG AA and AAA.
  • Icon-only buttons — the demo buttons carry no aria-label. Add aria-label="Edit" (or equivalent) to each button for screen reader users.
  • Semantics — replace <div class="label-target"> elements with native <button type="button" aria-label="…"> for keyboard navigation without extra JavaScript.

Browser compatibility

Requires CSS position: absolute, opacity, and transform — supported in all browsers since 2015. Zero JavaScript dependencies.

Chrome 60+✓ Full
Firefox 55+✓ Full
Safari 11+✓ Full
Edge 79+✓ Full
Mobile iOS✓ No hover
Android Chrome✓ No hover

On mobile and touch screens, <code>:hover</code> does not fire on tap: labels stay invisible. Add a <code>click</code> or <code>touchstart</code> handler that toggles a <code>.label-visible</code> class to work around the absence of hover.

The code

HTML structure to paste into your page (CSS + JS available with a premium account):

index.html — structure
<div class="anchor-demo">
  <div class="labels-scene">
    <button type="button" class="label-target label-target-1" aria-label="Edit">
      <span aria-hidden="true">✎</span>
      <span class="floating-label">Edit</span>
    </button>
    <button type="button" class="label-target label-target-2" aria-label="Favorites">
      <span aria-hidden="true">♥</span>
      <span class="floating-label">Favorites</span>
    </button>
    <button type="button" class="label-target label-target-3" aria-label="Share">
      <span aria-hidden="true">↗</span>
      <span class="floating-label">Share</span>
    </button>
  </div>
</div>
🔒 Unlock the full code — from €2.99 the first month

Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
top: -36px -36px Distance of the label above the button (on .floating-label). Increase for larger buttons, reduce to compact. Must remain negative to display above.
translateY(6px) 6px Micro-translation travel on hover entry. Drop to 3 px for a subtle effect, raise to 10 px for a more pronounced glide.
transition: opacity .25s, transform .25s .25s Label show/hide duration. .15s for snappy productivity tools, .4s for a softer consumer UI.
background: rgba(15, 15, 30, .92) rgba(15,15,30,.92) Label background color and opacity. Adapt to your theme — remember to update the ::after border-color accordingly.
border: 1px solid rgba(99, 102, 241, .3) rgba(99,102,241,.3) Accent border of the label. Change the color to your brand hue, or remove it for a borderless label.
font-size: .72rem .72rem Label text size. .65rem for dense interfaces, .8rem for better legibility.
transform: scale(1.15) 1.15 Button scale factor on hover. scale(1.05) for subtlety, scale(1.25) for more expressiveness.
cubic-bezier(.34, 1.56, .64, 1) elastic Spring curve on the button hover. Replace with ease-out to remove the bounce, or adjust the 2nd parameter (>1 = over-damped) to calibrate elasticity.

FAQ

No. The mechanism relies on CSS :hover, which does not fire on tap on iOS and Android. For touch surfaces, add a click or touchstart handler that toggles a .label-visible class on the button, and replace .label-target:hover .floating-label with .label-target.label-visible .floating-label.
Adjust the .floating-label position: for below, switch to top: calc(100% + 8px) and reverse the ::after (border-color: transparent transparent rgba(15,15,30,.92), bottom: 100%). For the right side, use left: calc(100% + 8px); top: 50%; transform: translateY(-50%) and adapt the caret.
No. Because .floating-label is position: absolute inside its .label-target parent (normal flow), it mechanically follows the button on scroll. JavaScript (getBoundingClientRect, ResizeObserver) is only needed if you switch to position: fixed for a tooltip that stays visible on screen at all times.