← Back to gallery
CSS

Wavy Underline Thickness Control

Native CSS text-decoration-style: wavy with animated thickness + offset — no decorative SVG layer needed. Three motion programs: a thickness breathe, a thickness + offset peak pulse, and a hue-shift color sweep.

wavy-underlinetext-decoration-styletext-decoration-thicknesstext-underline-offsetno-svgno-layout-shiftprefers-reduced-motion

Wavy underline · text-decoration breathing

Wavy Underline Thickness Control

Native wavy underline styling changes visual weight with text-decoration-thickness and underline-offset rather than drawing a separate SVG underline. Three variants demonstrate a thin inline link, a broader editorial mark, and a compact dense callout.

Thin wave · body copy

Inline Link

A thin squiggle breathes its thickness subtly so inline text stays readable while still signaling emphasis. The offset stays pinned — the underline never moves vertically. Em-based thickness scales with font size + browser zoom.

  • wavy underline
  • thickness only
  • subtle

Broader wave · headline

Editorial Mark

A thicker underline pulses both its weight AND its offset together — the line gets bolder as it pushes farther below the baseline, then holds the peak briefly before settling back. Headline-scale emphasis without positioning a separate decoration layer.

  • headline
  • thickness + offset
  • held peak

Compact copy · fixed offset

Dense Callout

A compact callout keeps thickness fixed and instead cycles the underline COLOR between accent and accent-2. Safer in dense UI where a thickness-changing squiggle would crowd neighboring text — only hue moves, geometry stays still.

  • dense UI
  • color cycle
  • static thickness

Underline inspector

Inline Link

  • wavy underline
  • thickness only
  • subtle

A thin squiggle breathes its thickness subtly so inline text stays readable while still signaling emphasis. The offset stays pinned — the underline never moves vertically. Em-based thickness scales with font size + browser zoom.

Helped you ship something? 🐟 Send my cat a churu

.wavy-text {
  color: #e0f2fe;
  text-decoration: underline wavy #38bdf8;
  text-decoration-thickness: 0.1em;
  text-underline-offset: 0.24em;
  /* Animate native CSS decoration props — no SVG, no positioned
     layer, no layout shift. */
  animation: wavy-breathe 2.40s ease-in-out infinite alternate;
}

@keyframes wavy-breathe {
  /* Thickness only — offset stays pinned so the underline never
     visibly shifts vertically. Range chosen wide enough to read. */
  from { text-decoration-thickness: 0.05em; }
  to   { text-decoration-thickness: 0.14em; }
}

@media (prefers-reduced-motion: reduce) {
  .wavy-text {
    animation: none;
    text-decoration-thickness: 0.1em;
    text-decoration-color: #38bdf8;
  }
}

How to make this

A wavy underline thickness control uses native text-decoration, then animates text-decoration-thickness and underline-offset in em units so the line scales with the text.

html
1<a class="wavy-underline-recipe" href="#">  Read the motion notes</a> <style>.wavy-underline-recipe {  color: #e0f2fe;  font: 800 clamp(1.2rem, 6vw, 2rem)/1.2 ui-sans-serif, system-ui;9  text-decoration-line: underline;  text-decoration-style: wavy;  text-decoration-color: #38bdf8;12  text-decoration-thickness: .08em;13  text-underline-offset: .24em;  text-shadow: 0 0 18px rgba(56, 189, 248, .14);  animation:    wavy-underline-recipe-breathe 2.4s ease-in-out infinite alternate;}18.wavy-underline-recipe:focus-visible {  outline: 2px solid #7dd3fc;  outline-offset: .35rem;}22@keyframes wavy-underline-recipe-breathe {  from {    text-decoration-thickness: .06em;    text-underline-offset: .22em;  }  to {    text-decoration-thickness: .16em;    text-underline-offset: .3em;  }}32@media (prefers-reduced-motion: reduce) {  .wavy-underline-recipe {    animation: none;    text-decoration-thickness: .1em;    text-underline-offset: .24em;  }}</style>

Annotated snippet

  1. Line 1Use a real link when the underlined phrase navigates. The underline treatment should not turn static text into fake interactivity.
  2. Line 9Native text-decoration keeps the underline attached to the text instead of managing a separate positioned element.
    PitfallWhy use native text-decoration instead of a pseudo-element underline?

    Native decoration follows text metrics, wraps with inline text, and scales naturally with font size. A pseudo-element can work for headings, but it is easier to misalign on wrapped inline copy.

  3. Line 12Thickness is expressed in em so the wave scales with font size and browser zoom. Pixel values can look too thin on large text and too heavy on small text.

    Two stacked links — small caption (.85rem) and headline (2rem). before locks thickness to a fixed 3px so the same line looks chunky under small copy and pencil-thin under the headline. after uses .1em — at .85rem that is ~1.4 px, at 2rem it is ~3.2 px, the underline weight tracks the type scale.

    PitfallShould underline thickness use px or em?

    Use em for text-relative weight. It responds to zoom and font size, which is especially important when the same underline style appears in body copy and headings.

  4. Line 13Underline offset controls breathing room from the baseline. Pair it with thickness changes so a heavier wave does not crowd descenders.

    Same word with three descenders (p, p, y), same heavy wavy decoration (thickness .18em on both), same color alpha breath (55% → 100%), text-decoration-skip-ink: none so the wave is drawn through everything it meets. Only text-underline-offset differs. 0 keeps the wave at the default position, where it crosses the descenders of p, p, y — the wave visibly cuts across the glyph strokes. .28em pushes the wave clear of the descenders so the same heavy crests stay on their own line. (Animating thickness redraws the wave shape on every frame and looks stepped; animating the alpha keeps the breathing smooth.)

    PitfallCan animated wavy underlines hurt readability?

    Yes. Keep the range subtle for body text and reserve stronger pulses for short labels or editorial marks. Dense UI often works better with color changes than thickness changes.

  5. Line 18Keep a separate focus-visible outline. A decorative underline can be part of the link style, but it is not enough by itself for keyboard focus.
    PitfallCan animated wavy underlines hurt readability?

    Yes. Keep the range subtle for body text and reserve stronger pulses for short labels or editorial marks. Dense UI often works better with color changes than thickness changes.

  6. Line 22The keyframe changes decoration geometry only. It does not change line height, text width, or surrounding layout.
    PitfallCan animated wavy underlines hurt readability?

    Yes. Keep the range subtle for body text and reserve stronger pulses for short labels or editorial marks. Dense UI often works better with color changes than thickness changes.

  7. Line 32Reduced motion freezes the underline at a moderate static weight. The emphasis remains visible without a breathing loop.
    PitfallHow should reduced motion apply to wavy underlines?

    Stop the breathing or color cycle and keep a static underline with enough contrast. Do not remove the underline if it communicates link affordance or emphasis.

Other pitfalls

Which browsers support text-decoration-thickness animation?
Modern Chromium, Firefox, and Safari support the core decoration properties. Animation smoothness can vary, so a static underline fallback should still look acceptable.

Notes

Overview

Native CSS wavy underline via text-decoration-style: wavy with animated text-decoration-thickness and text-underline-offset. No decorative SVG layer and no per-letter spans — just CSS text-decoration properties on the actual text node. Three motion programs: thickness breathe, thickness + offset peak pulse, hue-shift color sweep.

When to use it

Reach for wavy underlines on highlighted phrases, marketing callouts, and editorial emphasis — anywhere <em> needs visual amplification. Skip it on links (the wavy already means “spelling error” to most users) and on dense paragraph copy where the underline crowds adjacent lines.

How it works

Set text-decoration-line: underline + text-decoration-style: wavy on the element. Two animatable properties drive the motion: text-decoration-thickness (e.g. 1px to 3px) and text-underline-offset (e.g. 2px to 6px). A @keyframes rule animates either or both. For color sweeps animate text-decoration-color through a hue range. The wave geometry itself is fixed — you cannot animate the wave amplitude or frequency directly without falling back to an SVG underline overlay.

Production gotchas

Animating thickness past ~4px crowds the line below in dense paragraph copy — clamp the maximum thickness based on line-height. Browsers differ on whether text-decoration-thickness is interpolated smoothly (Chromium yes, Firefox yes as of recent versions, Safari sometimes snaps); accept that the breathe may be slightly less smooth in older Safari. Watch text-underline-offset on emoji or mixed-font lines — the offset is calculated per-glyph metric and can produce uneven underlines under those characters.

Accessibility

Native text-decoration underlines respect user underline-style preferences and forced-colors mode for free — one of the strongest reasons to use this over an SVG fake. Under prefers-reduced-motion: reduce drop the animation so the underline is static at its rest thickness. Wavy underlines on links can confuse users with spelling-check muscle memory — use a different decoration-style (solid, double) for actual links.

References

Implementation depth

Native text decoration is usually better than drawing an SVG underline for every link. text-decoration-style, text-decoration-thickness, and text-underline-offset keep the underline attached to real text metrics.

Tune thickness per font size. A decorative wave that works under a large heading can muddy small inline links, so keep body-copy underlines quieter and avoid animation when the underline is carrying accessibility meaning.