Permalink
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
124 lines (100 sloc) 5.16 KB
categories date tags title
programming
2018-12-19
css
Animated Multiline Link Underlines with CSS

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.

{{< video 2sKxENF >}}

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.

{{< video XWPhTQM >}}

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.

{{< video 8pxxwkT >}}

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 {
    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.

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.