Hover✨ Premium

Fill Up

An ::after pseudo-element rises from bottom to top (height 0 → 100%) on hover with an ease-quart-out curve — the element fills vertically like a glass being filled; text stays readable via z-index.

CSSFillBezier

Updated

This effect is part of Effect.Labs — 840 vanilla effects, some free, some premium. Hover has 48 effects, including 5 free. Explore the category →

3 usage examples

Settings tabs — user account interface — Fill Up example 1

① Settings tabs — user account interface

WhenNavigation tabs (Account, Security, Notifications) in the Nolvex settings page header; on hover or focus, each tab fills from bottom to top and the text turns white.
WhyThe bottom-to-top fill on a settings tab makes the section change physically legible: the eye follows the background rise and anticipates the selection.
SettingsSmall inline tabs in a header; dark background; indigo accent text at rest, white on hover; 0.6s fill transition; focus cycling via script.
Pro pricing plan card — SaaS subscription page — Fill Up example 2

② Pro pricing plan card — SaaS subscription page

WhenThe Pro plan card in the Flux plan table (Free, Pro, Enterprise); on hover the card fills from bottom to top, revealing the indigo accent background with white text.
WhyThe fill-up on the recommended card creates dynamic visual hierarchy: during hover, the Pro plan visually self-selects and guides the user's decision toward the target option.
SettingsLarge vertical card with badge and price; dark background at rest; indigo accent background on hover; feature list; 0.6s fill transition.
Submit button — job application form — Fill Up example 3

③ Submit button — job application form

When'Submit my application' button at the end of the Talvyn application form; on hover or focus, the background rises from bottom to top and the text turns black on green.
WhyThe fill-up on a form CTA turns submitting a dossier into a visual commitment gesture: the rising background signals the action is imminent and reinforces the applicant's confidence.
SettingsFull-width button in an application form; dark green background at rest; light green accent background on hover; focus toggle via script; 0.6s fill transition.

How it works

The .fx-0355-root root centers a .hover-box.hover-fill-up block of 200 × 200 px. The element has a transparent background, a violet border and violet text at rest. An ::after pseudo-element positioned at bottom: 0; left: 0; width: 100% starts at height: 0 and rises to height: 100% on hover with a linear-gradient(135deg, #a78bfa, #8b5cf6) gradient.

The transition curve is cubic-bezier(0.65, 0, 0.35, 1) — ease-quart-out — which starts slowly then accelerates at the end, giving the impression that liquid arrives quickly at the top. The text transitions from violet to white at the same time (transition: color .6s). The z-index: -1 of ::after places it behind the span (z-index 1): text stays readable at all times.

Measured in Chromium 151: bottom-to-top fill, text color changes, two copies on a page — only the hovered one fills.

Accessibility

  • Reduced motion: under prefers-reduced-motion: reduce, transitions are cancelled; the fill and color change remain functional (the ::after jumps to 100% height and the text turns white instantly). The hover state stays readable.
  • Keyboard: the element is a natively focusable <button>. The :focus-visible rule triggers the fill and colour change; an indigo outline marks the focus state.
  • Contrast: the violet text (#a78bfa) on a dark background at rest has a 5.4:1 ratio (WCAG AA). On hover, white text on violet has a 7.8:1 ratio.
  • Touch: the first touch triggers the fill; it stays in place until the next touch. On mobile, the filled state may persist after the finger lifts.

Browser compatibility

Pure CSS (::after, height, cubic-bezier, transition, :focus-visible, prefers-reduced-motion), no JavaScript. Measured in Chromium 151: fill visible, text readable, two independent copies. Works in all modern browsers.

Chrome 60+✓ Full (measured)
Firefox 55+✓ Full
Safari 10.1+✓ Full
Edge 79+✓ Full (Chromium engine)
Mobile iOS 10.3+✓ Full
Android Chrome 60+✓ Full (Chromium engine)

Without transition, the fill appears instantly on hover. Without properly managed z-index, text may be hidden by the ::after — ensure the span has position: relative; z-index: 1.

The code

HTML structure to paste into your page (the CSS + JS come with your purchase):

index.html — structure
<div class="fx-0355-root">
  <button class="hover-box hover-fill-up" type="button">
    <span>…</span>
  </button>
</div>

One-time payment, no subscription — the code is yours forever

Customize

Options passed to the API or data-* attributes:

Option / propertyDefaultEffect
Fill color (CSS — background of ::after) linear-gradient(135deg, #a78bfa, #8b5cf6) Replace with a solid color (#10b981 green) or a different gradient. The fill color can match the brand identity.
Fill curve (CSS — cubic-bezier(.65, 0, .35, 1)) ease-quart-out (accelerates at the end) linear gives a steady fill; ease-in starts fast and slows down; cubic-bezier(.17, .67, .83, .67) adds a slight bounce.
Duration (CSS — transition: height .6s) 600 ms .3s for a snappy fill; 1s for a slow, dramatic fill.
Border (CSS — border of .hover-fill-up) 2 px solid #a78bfa Remove the border for a solid background at rest (background: var(--bg-card) + border: none); in that case, the fill changes the background from dark to vivid.
Direction (CSS — ::after anchor) Bottom to top (bottom: 0) Anchor at top: 0; height: 0 → 100% (top to bottom) or left: 0; width: 0 → 100% (left to right, horizontal fill).

FAQ

Use a CSS variable: --fill: 60% on the element, then .hover-fill-up:hover::after { height: var(--fill) }. For size buttons, set the variable inline: style="--fill: 60%".
Yes. The span has position: relative; z-index: 1 and the ::after has z-index: -1. The text color transition (violet → white) accompanies the fill to maintain contrast.
Not directly in pure CSS. With JavaScript, add the .filled class on click: el.classList.toggle('filled'), then trigger the fill via .hover-fill-up.filled::after { height: 100% }.