Underline Slide
Pure CSS animated underline: transform: scaleX() + dual transform-origin — the bar slides in from the left on hover and exits to the right on mouse-out. Zero JS.
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



How it works
The effect is 100% CSS, no JavaScript. The .link-underline-slide::after pseudo-element creates a 2 px bar (background: #6366f1, indigo) spanning the full link width (width: 100%), anchored at the bottom with position: absolute; bottom: 0. By default, transform: scaleX(0) hides it; only the transform property is transitioned (transition: transform .3s). At the same time, .nav-link-demo transitions its color from #a1a1aa (zinc-400) to #ffffff over the same 0.3 s.
The core mechanism is a dual transform-origin switch. At rest: transform-origin: right center — the scaling pivot is anchored to the right. On :hover: transform-origin: left center — the pivot instantly flips to the left (the property is not transitioned). Only scaleX is interpolated.
The double anchor creates an asymmetric animation. On hover-in: pivot at left, scaleX goes 0→1 — the bar grows from the left edge toward the right. On hover-out: pivot flips back to right, scaleX goes 1→0 — the left edge retreats toward the right anchor while the right edge stays fixed. The underline enters from the left and exits to the right without ever retracing the same path, giving the impression of a directional slide.
Accessibility
- prefers-reduced-motion not present in the code. CSS transitions run even when the user has requested reduced motion. Add manually:
@media (prefers-reduced-motion: reduce) { .link-underline-slide::after { transition: none; } }. - Text contrast meets WCAG AA in both states:
#a1a1aaon#0a0a0f(≈ 5.8:1 at rest) and#ffffffon#0a0a0f(21:1 on hover). - The effect relies solely on
:hover— notabindexor:focus-visiblein the base code. For<span>elements, addtabindex="0"and.link-underline-slide:focus-visible::after { transform: scaleX(1); transform-origin: left center; }for keyboard users. - The hover signal combines two independent visual cues (text color + underline) — meets WCAG 1.4.1 without relying on color alone.
- No
aria-*attributes in the base code. If elements remain<span>, addrole="link"; if they are<a>tags, a validhrefis sufficient for accessibility.
Browser compatibility
Uses transform, transform-origin, and ::after — supported in all modern browsers since IE 9. Zero external dependencies.
Without CSS transition support (very old browsers), the underline appears and disappears instantly — no JS errors, navigation remains fully functional.
The code
HTML structure to paste into your page (CSS + JS available with a premium account):
<div class="nav-demo">
<span class="nav-link-demo link-underline-slide">Home</span>
<span class="nav-link-demo link-underline-slide">Services</span>
<span class="nav-link-demo link-underline-slide">Contact</span>
</div>
Full HTML + CSS + JS, copy-paste ready — with hundreds of premium effects.
Customize
Options passed to the API or data-* attributes:
| Option / property | Default | Effect |
|---|---|---|
| --text-secondary | #a1a1aa | Text color at rest (root CSS variable). Adjust to your navigation gray. |
| --text-primary | #ffffff | Text color on hover. Replace with your primary color if the background isn't black. |
| background in ::after | #6366f1 | Underline bar color. Replace with your brand color or use currentColor to inherit from the text. |
| height in ::after | 2px | Bar thickness. 1 px = subtle (footer), 3–4 px = prominent (active tabs). |
| transition: transform .3s in ::after | 0.3s | Underline animation duration. 0.2 s = snappy and responsive, 0.4 s = softer. |
| transition: color .3s in .nav-link-demo | 0.3s | Text color transition duration. Sync with the underline duration for a unified feel. |
| transform-origin (default state and :hover) | right / left | Swapping the two values (left center by default, right center on hover) reverses the animation direction: enters from the right, exits to the left. |
FAQ
<a>, <span>, <li>, <button>) — just apply the class link-underline-slide and make sure the element has position: relative. On an <a>, add text-decoration: none to remove the browser's native underline before your animated bar takes over.transform-origin values in the CSS: set left center in the default state and right center in the :hover::after block. The underline will then enter from the right and exit to the left.:hover. For keyboard-navigable links, add .link-underline-slide:focus-visible::after { transform: scaleX(1); transform-origin: left center; }. This shows the full underline on focus and meets WCAG 2.4.7 (visible focus).