Danny Guo | 郭亚东

Animated Multiline Link Underlines with CSS

Updated on  ·  Published on
577 words  ·  ~3 minutes to read

One benefit of building my personal website from scratch instead of using a theme made by someone else is that I can start from the browser’s defaults and gradually add my own flourishes. I strive to keep my site lean, but making it personal is also kind of the point. There is a spectrum of gratuitous touches between the spartan pages of Hacker News and Craigslist on one end and the sensory overload of old MySpace on the other.

I ran across a site that had fancy, animated underlines for links, and I wanted to add a similar effect to my site. It was important to me to use a pure CSS solution. For something as frivolous as this, I didn’t want to add JavaScript that has a risk of causing a performance issue or frustrating behavior (see scroll hijacking).

Here’s what the effect looks like now.

Implementation

The topic of drawing lines under text on the web can be surprisingly complicated, depending on how far you are willing to stray from text-decoration: underline and which details (like clearing descenders) you care about.

I investigated a few approaches:

Both of them essentially remove the default text-decoration and add a simulated border using pseudo-elements. The border is then animated by CSS transitions. Unfortunately, these solutions have one drawback: they don’t work properly if the link spans more than one line. The underline only appears on the first line.

I eventually found a CodePen by Shaw that doesn’t have this flaw. I modified the CSS until I got to a solution that looks good to me.

Here is the relevant code. You can use this repl to play around with it.

a {
    text-decoration: none;
    background-image: linear-gradient(currentColor, currentColor);
    background-position: 0% 100%;
    background-repeat: no-repeat;
    background-size: 0% 2px;
    transition: background-size .3s;
}

a:hover, a:focus {
    background-size: 100% 2px;
}

Let’s go through this approach part by part. First, we turn off the default text-decoration for links.

We want to use background-image because it can span multiple lines. While we could supply an actual image, we only want to draw a line, so we use linear-gradient, which generates an image for us. Normally, it’s used to create a gradient between two different colors, but I want the underline to just be the same color as the link, so I use currentColor for both the beginning and the end of the gradient. currentColor tells the browser to use the element’s computed color property.

We use background-position to place the image in the bottom left corner. 0% sets the horizontal position, and 100% sets the vertical position.

We turn off background-repeat to prevent it from creating multiple instances of the image to fill the entire background of the link.

We use background-size to make the image zero pixels wide and two pixels tall. It has zero width because the underline should only appear on hover.

We set a transition on background-size, so any change to the property will take 0.3 seconds to complete.

On link hover, we change the width of the image to 100%, creating a full underline, and transition takes care of the animation. As nickels55 suggests, we also want the effect to happen on focus for those who use keyboard navigation. Thanks to nickels55 for keeping accessibility in mind.

And that’s it! I was very happy with how small the commit ended up being. If you’d like to add something similar to your site, feel free to take this implementation, or check out some other animated underline effects for inspiration.


← Using Mailgun for a Free Custom Domain Email Address How to Add Copy to Clipboard Buttons to Code Blocks in Hugo →

Follow me on Twitter or Mastodon or subscribe to my newsletter or RSS feed for future posts.

Found an error or typo? Feel free to open a pull request on GitHub.