Animated underline on hover (pure CSS)
Tags: html, css
Published: 2021-02-26 04:51:51

I'm sure you have seen the design principle being used on many of the modern websites. There's a set of links (typically in a nav bar, or as part of a tabbed interface), and when you hover over them, a nice animated underline appears, which expands outward from the center, and then disappears once you take your mouse off of it. If you wondered how that was done, I am happy to report to you that there is a way to do just that, purely with CSS (no JavaScript involved). Let's get started.

## Pseudo-elements and pseudo-classes
I figured it'd be nice to start with a refresher on pseudo-elements and pseudo-classes. In fact, we need to know the distinction between them because they look very similar. A pseudo-element sort of... temporarily converts a part of your HTML into an element, so that it can be styled on its own. If you're having trouble wrapping your head around this concept, consider the selector `span::first-letter`. Here, the pseudo-element in question is `first-letter`, which picks the very first letter in the `span` and styles it according to the rules set. A pseudo-class, on the other hand, is styling that does not exist normally, but is applied to an element under specific conditions. An example of that would be the `:hover` pseudo-class, which helps us apply a different style set on an element, when the user hovers on it with their mouse.

## `::after`thought
So, there are multiple ways to achieve an underline. You could use any of these CSS attributes - 
* `text-decoration` (set to `underline`)
* `border`
* `box-shadow`

In my experience, however, I have found that using the `::after` psuedo-element achieves the best and most aesthetically pleasing results. Recall that `::after`, by virtue of it being a pseudo-element, sort of _creates_ a new element where it didn't exist before. In case of `::after`, that element is _between the content and the closing tag_.

>There seems to be a common misunderstanding that the `::before` and `::after` pseudo-elements are created outside the parent element. This is wrong. In reality, their names refer to their position with respect to the content (or inner HTML, if you will) inside the parent. They are both children of the element(s) which they are declared for.

So, let's get started setting things up. Our HTML doesn't need to be complicated, just a link or two will be fine. We don't need to add anything here, because pseudo-elements will be created per our requirement anyway. 

```html
<a>Home</a>
<a>News</a>
```

Let's also put some default styling on the `a` tags - 
```css
a {
    display: inline-block;
    width: 120px;
    font-size: 20px;
    text-align: center;
    color: tomato;
    font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
    font-weight: 600;
    cursor: pointer;
}
```
Now, we'll create an `::after` pseudo-element which exists but is hidden under normal circumstances - 
```css
a::after {
    content: "";
    display: block;
    margin-top: 10px;
    margin-left: auto;
    margin-right: auto;
    height: 2px;
    width: 0px;
    background-color: tomato;
}
```
Setting the `width` to `0px` is what hides it from view. We've also used the trusted trick of setting the left and right margins to `auto` to center it horizontally.

Now, on `hover`, we want its `width` to grow. And in order to make it animate smoothly, all we need to do is add a `transition` attribute.

```css
a:hover::after {
    width: 100%;
    transition: all 0.4s;
}
```

>This CSS rule is also a cool example that uses both a pseudo-class (`:hover`) and a pseudo-element (`::after`)

And believe it or not, that's all there's to it! Super-simple, like I promised. You can check out the full sandbox below.

{% codesandbox mystifying-fog-7p9o3 %}

Stay safe, and happy coding!