An underline draws under the text, runs on past the last letter and grows an arrowhead, so the link points where it goes. The head is a rotated border corner that waits for the line.
Also known as: underline turns into arrow, arrow line hover, read more arrow underline.
<a class="hfx-link-arrow-underline" href="#">Keep reading</a>
.hfx-link-arrow-underline {
--c: var(--hfx-color, #3b82f6);
position: relative;
display: inline-block;
color: var(--c);
font: 600 calc(var(--hfx-size, 16px) * 1.25)/1.3 system-ui, sans-serif;
text-decoration: none;
margin-right: 1.1em;
padding-bottom: 0.3em;}
.hfx-link-arrow-underline::before,
.hfx-link-arrow-underline::after {
content: "";
position: absolute;
}
.hfx-link-arrow-underline::before {
left: 0;
bottom: 0.1em;
width: calc(100% + 0.95em);
height: 0.09em;
border-radius: 1em;
background: var(--c);
transform: scaleX(0);
transform-origin: left;
transition: transform 0.4s cubic-bezier(0.65, 0, 0.35, 1);
}
.hfx-link-arrow-underline::after {
left: calc(100% + 0.55em);
bottom: -0.035em;
width: 0.36em;
height: 0.36em;
border-top: 0.09em solid var(--c);
border-right: 0.09em solid var(--c);
border-radius: 0 0.05em 0 0;
opacity: 0;
transform: translateX(-0.35em) rotate(45deg);
transition: opacity 0.15s ease, transform 0.25s ease;
}
.hfx-link-arrow-underline:is(:hover, :focus-visible)::before { transform: scaleX(1); }
.hfx-link-arrow-underline:is(:hover, :focus-visible)::after {
opacity: 1;
transform: translateX(0) rotate(45deg);
transition: opacity 0.15s ease 0.28s, transform 0.35s cubic-bezier(0.34, 1.56, 0.64, 1) 0.28s;
}
@media (prefers-reduced-motion: reduce) {
.hfx-link-arrow-underline, .hfx-link-arrow-underline *, .hfx-link-arrow-underline::before, .hfx-link-arrow-underline::after, .hfx-link-arrow-underline *::before, .hfx-link-arrow-underline *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}--hfx-color on the element or a parent.
Currently previewing #3b82f6.--hfx-size. Every other dimension is in
em, so the whole thing scales together. Currently previewing 16px.transition or animation
shorthand. Staggered delays are relative, so they keep their rhythm.