25 CSS Text Animations 17 / 25

CSS Liquid Fill Text Animation

Text appears to fill with liquid from bottom to top using a moving gradient mask and clip-path — a striking progress-indicator text technique.

Pure CSS MIT licensed
Live Demo Open in tab
Open in playground

The code

<div class="ta-17">
  <div class="ta-17__stage">
    <div class="ta-17__container">
      <h2 class="ta-17__outline">FILL</h2>
      <h2 class="ta-17__liquid">FILL</h2>
    </div>
    <p class="ta-17__sub">clip-path inset · -webkit-text-stroke · liquid rise</p>
  </div>
</div>
.ta-17, .ta-17 *, .ta-17 *::before, .ta-17 *::after {
  margin: 0; padding: 0; box-sizing: border-box;
}
.ta-17 ::selection { background: #0369a1; color: #e0f2fe; }

.ta-17 {
  --bg: #020c18;
  --water: #0ea5e9;
  --deep: #0369a1;
  min-height: 100vh;
  background: var(--bg);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 2rem;
  font-family: 'Syne', 'Helvetica Neue', sans-serif;
}

.ta-17__stage { text-align: center; }

.ta-17__container {
  position: relative;
  display: inline-block;
  line-height: 1;
}

.ta-17__outline,
.ta-17__liquid {
  font-size: clamp(4rem, 14vw, 8rem);
  font-weight: 900;
  letter-spacing: 0.08em;
  margin: 0;
  line-height: 1;
}

.ta-17__outline {
  -webkit-text-stroke: 2px rgba(14, 165, 233, 0.35);
  color: transparent;
}

.ta-17__liquid {
  position: absolute;
  top: 0; left: 0;
  background: linear-gradient(to top, var(--deep) 0%, var(--water) 60%, #7dd3fc 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  clip-path: inset(100% 0 0 0);
  animation: ta-17-rise 2.4s cubic-bezier(0.4, 0, 0.2, 1) 0.5s forwards;
}

@keyframes ta-17-rise {
  to { clip-path: inset(0% 0 0 0); }
}

.ta-17__sub {
  font-size: 0.65rem;
  color: #0c2a40;
  margin-top: 0.6rem;
  letter-spacing: 0.1em;
  font-family: 'Courier New', monospace;
}

@media (prefers-reduced-motion: reduce) {
  .ta-17__liquid { animation: none; clip-path: inset(0% 0 0 0); }
}

How this works

The technique layers two copies of the text — an unfilled outline using -webkit-text-stroke as the base, and a filled solid colour version clipped with clip-path: inset() that starts at the bottom edge and animates upward. The clip-path: inset(100% 0 0 0) value clips from the top, hiding the filled text entirely. Animating it to inset(0% 0 0 0) progressively reveals the filled layer from bottom to top over the stroke outline.

A subtle wave distortion on the liquid surface is added by animating a pseudo-element with a radial-gradient ellipse that moves sinusoidally across the top edge of the fill, creating the meniscus wobble of a rising liquid surface. The liquid colour uses a two-tone gradient — darker at the bottom, brighter at the surface — reinforcing the depth cue of a column of coloured fluid.

Customize

  • Change the fill speed by adjusting animation-duration on the ::after clipped text — 2s is dramatic, 6s is slow and satisfying.
  • Change the fill direction from bottom-to-top to left-to-right by using inset(0 100% 0 0) as the start state and inset(0 0 0 0) as the end.
  • Combine with a percentage counter displayed above the text to create a loading or skill-level indicator where the fill percentage is data-driven via JS.
  • Change the liquid colour from a blue water effect to lava by using a gradient of #ef4444 to #f97316 with an orange glow on the surface wave.
  • Loop the animation with a drain phase — adding a second keyframe section that refills from 0% to 100% — for an infinite animated fill-and-drain cycle.

Watch out for

  • -webkit-text-stroke has no non-prefixed version in the CSS spec as of 2025 — it's a WebKit extension that works in Chrome, Safari, and Edge but is not in Firefox's standard implementation.
  • The clip-path approach requires the filled copy to be position: absolute layered exactly over the stroke text — any font-rendering subpixel difference between the two can cause a visible double-image.
  • Gradient fills inside clipped text can produce aliasing at the clip boundary in Safari — adding -webkit-font-smoothing: antialiased and a very slight transform: translateZ(0) mitigates this.

Browser support

ChromeSafariFirefoxEdge
55+ 10.1+ 71+ 55+

-webkit-text-stroke is widely supported experimentally. Firefox renders the stroke but may differ in exact weight; always test cross-browser.

Search CodeFronts

Loading…