Underline Link Animation
Two CSS-only underline link variants built on pseudo-elements. The default version draws a line from left to right on hover. The alt version uses two pseudo-elements with staggered transition-delay to erase the existing underline from right to left then draw a new one from left to right.
Code
<div class="link-group">
<a data-underline-link href="#" class="underline-link">Underline Link</a>
<a data-underline-link="alt" href="#" class="underline-link">Animation</a>
</div>.link-group {
gap: 1em;
justify-content: center;
font-size: 3em;
display: flex;
}
.underline-link {
color: inherit;
font-size: 1em;
line-height: 1.25;
}
[data-underline-link] {
text-decoration: none;
position: relative;
}
[data-underline-link]::before,
[data-underline-link="alt"]::before,
[data-underline-link="alt"]::after {
content: "";
position: absolute;
bottom: -0.0625em;
left: 0;
width: 100%;
height: 0.0625em;
background-color: currentColor;
transition: transform 0.735s cubic-bezier(0.625, 0.05, 0, 1);
transform-origin: right;
transform: scaleX(0) rotate(0.001deg);
}
[data-underline-link="alt"]::before {
transform-origin: left;
transform: scaleX(1) rotate(0.001deg);
transition-delay: 0.3s;
}
[data-underline-link="alt"]::after {
transform-origin: right;
transform: scaleX(0) rotate(0.001deg);
transition-delay: 0s;
}
@media (hover: hover) and (pointer: fine) {
[data-hover]:hover [data-underline-link]::before,
[data-underline-link]:hover::before {
transform-origin: left;
transform: scaleX(1) rotate(0.001deg);
}
[data-hover]:hover [data-underline-link="alt"]::before,
[data-underline-link="alt"]:hover::before {
transform-origin: right;
transform: scaleX(0) rotate(0.001deg);
transition-delay: 0s;
}
[data-hover]:hover [data-underline-link="alt"]::after,
[data-underline-link="alt"]:hover::after {
transform-origin: left;
transform: scaleX(1) rotate(0.001deg);
transition-delay: 0.3s;
}
}Guide
Default Variant
Add data-underline-link to any link. A single ::before pseudo-element sits at scaleX(0) with transform-origin: right at rest. On hover it switches to transform-origin: left and scales to 1, drawing the line left to right.
Alt Variant
Add data-underline-link="alt" for a two-phase swap. ::before starts at scaleX(1) (visible) and collapses immediately on hover with no delay. ::after starts at scaleX(0) and draws in after a 0.3s delay — creating an erase-then-redraw effect.
Parent Hover
Both variants also respond to a data-hover attribute on a parent element. Add data-hover to a wrapper and the underline will animate when the wrapper is hovered, not just the link itself — useful for card hover states.
Customisation
The underline thickness is 0.0625em and offset is -0.0625em below the baseline — both scale with font-size. Adjust the transition duration (0.735s) and transition-delay (0.3s on the alt variant) to control the timing.