DEV Community


Posted on

Animated underline on hover (pure CSS)

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.


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.

Enter fullscreen mode Exit fullscreen mode

Let's also put some default styling on the a tags -

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;
Enter fullscreen mode Exit fullscreen mode

Now, we'll create an ::after pseudo-element which exists but is hidden under normal circumstances -

a::after {
    content: "";
    display: block;
    margin-top: 10px;
    margin-left: auto;
    margin-right: auto;
    height: 2px;
    width: 0px;
    background-color: tomato;
Enter fullscreen mode Exit fullscreen mode

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.

a:hover::after {
    width: 100%;
    transition: all 0.4s;
Enter fullscreen mode Exit fullscreen mode

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.

Stay safe, and happy coding!

Top comments (0)