Animated underline on hover (pure CSS)
(Originally posted on https://dev.to/debadeepsen/animated-underline-on-hover-pure-css-4bm6)
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 tounderline
) 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.
<a>Home</a>
<a>News</a>
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;
}
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;
}
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;
}
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!