I was working on a client site last week, and had mocked up a regular ol’ text navigation with a border-bottom on it. I was gonna just put a border on it and call it a day, but I wanted to do something more with a sort of animation.
I decided to make the line expand from the center, as expanding from the left seemed to give the text an unbalanced feel. For the life of me, I can’t figure out where I got the inspiration for this idea. I must have seen this affect before somewhere.
html and scss without the fanciness
The markup…
<nav class="nav-secondary">
<ul>
<li><a href="^_^">Home</a></li>
<li><a href="^_^">Who We Are</a></li>
<li><a href="^_^">Blog</a></li>
</ul>
</nav>
with some base styling:
$red: #ef4035;
$grey: #b0a7a7;
.nav-secondary {
ul {
width: 100%;
}
li {
text-align: center;
display: inline-block;
float: left;
padding: 0 6%;
white-space: nowrap;
}
a {
color: darken($grey, 10%);
text-decoration: none;
padding-bottom: 6px;
display: block;
}
}
Why use psuedo elements?
Obviously, we can’t just put a border on the bottom of the anchor and anmiate width, because our anchor text wouldn’t be visible until hover. I decided to use a pseudo element for the “border” so we can have a width: 0;
before hover. I also split the line into two elements, :before
and :after
, which breaks the “border” into two segments that we can animate separately.
$red: #ef4035;
$grey: #b0a7a7;
.nav-secondary {
ul {
width: 100%;
}
li {
text-align: center;
display: inline-block;
float: left;
padding: 0 6%;
white-space: nowrap;
}
a {
color: darken($grey, 10%);
text-decoration: none;
padding-bottom: 6px;
display: block;
&:after {
clear: both;
display: block;
content: "";
position: relative;
left: 50%;
height: 3px;
background: $red;
border-radius: 6px;
}
}
}
From there, we set the initial width: 0
, the :hover
and :focus
to width: 50%
(because there are 2 “borders”), and add a transition to animate the width.
$red: #ef4035;
$grey: #b0a7a7;
.nav-secondary {
ul {
width: 100%;
}
li {
text-align: center;
display: inline-block;
float: left;
padding: 0 6%;
white-space: nowrap;
}
a {
color: darken($grey, 10%);
text-decoration: none;
padding-bottom: 6px;
display: block;
&:after {
clear: both;
display: block;
content: "";
position: relative;
width: 0;
left: 50%;
height: 3px;
background: $red;
@include transition(width .2s, left .2s);
border-radius: 6px;
}
&:hover, &:focus {
&:after {
width: 100%;
left: 0;
}
}
}
}
Final working nav
Check out this Pen!
Browser support
It turns out that animating generated content is not supported in all browsers. Chris Coyier has a post about it, but the long and short of it is that it’s not supported in IE9 (is supported in 10), not supported in current Opera or current Safari. This didn’t bug me too much because it degrades really well, and support isn’t that far off.
A note about performance
After I had put this on CodePen, vsync found a more straightforward approach to the solution by using text-align: center
and only one pseudo element. I just happen to be looking at it on my 2008 MacBook Pro, and the framerate was a little jerky. I took a look in Chrome Dev Tools, and it was for sure reprinting quite a bit. I’m not trying to dis on vsync‘s code. It was just dumb luck that I came up with a more efficient solution. But I just wanted to note it.
4 replies on “Expanding underline navigation with css”
Thank you for the great tutorial.
The way you have explained it is helpful.
I wanted to clarify (and sorry if it is n00b question). The animation is a result of adding a background to the text which is shown when the hover event occurs. Is this correct?
The code vsync has works well in the latest version of Chrome but I could get my head around your code versus Vsync’s.
I’m not 100% sure why, but it seems to be that the
text-align: center;
solution seems to be do more calculation/paints than the 2 element solution.Hi. Thank you for this tutorial.
I want to ask you if the red underline could appear from bottom: starting from height: 0 and smoothly increasing to 3px. It could be done modifying your navbar? Thanks in advance
Yeah, I forked my Pen to make it animate vertically: http://codepen.io/rtvenge/pen/Dzgsu
I ended up having to animate a
margin-top
on it to get it to animate from bottom to top.