Code a Useful Expanding Vertical Navigation Menu

by on 6th February 2012 with 31 Comments

screenshot

Today we have yet another awesome step-by-step CSS project for you! This time around we’re going to build a super useful expanding vertical navigation menu. It’s a great way to hide a lot of links in a fairly small space and the animations will add a nice touch to your site.

Even if you’re a complete beginner, you should be able to pull this off. I’ll guide you along every step of the way and explain how each chunk of code works so you can implement these same techniques in future projects and deepen your understanding of CSS. Let’s get started!

The Concept

Before we start coding, it’s always helpful to lay out the rough concept of what you want to achieve so you can wrap your brain around what’s going to be involved. The item we’re building today is a vertical navigation menu that’s in a sort of modified accordion format (get a sneak peek of the finished product here).

screenshot

As you can see, the sections on the bottom are closed by default and slide open when you over over them. However, to add some nice variation we’ll also include a section that stays open all of the time. In the main section that is always open we’ll include a brief welcome message and in the sections that slide open will be sub-sections of navigation links.

Now that we have a good idea of where we’re going, let’s start outlining the structure in our HTML.

The HTML

The first thing we’re going to do is toss in some nice HTML5 to wrap the menu in. The new nav element provides a beautifully semantic container for our menu.


Now let’s think about how our menu is going to be structured. We’re not simply going to have a list of links, each bar represents a link with an additional area below it. We’ll wrap these up in a div. Then within each div we’ll need a main link (the colored bar) and a list of sub-links (the white area). Assuming that this item will be thrown into a site that already has some default styling, let’s arbitrarily settle on h4 for the main link and a simple unordered list for the rest.

We can copy, paste and modify this section of code to make up the various pieces of our navigation menu. Here we have a Portfolio, About, and Contact section, each with three sub-links. Each section is given the same class (menu-item) so we can style them in one go.

I wanted to focus on those areas first because they’re all the same, but remember that the top section is actually different, both in functionality and content. Instead of holding an unordered list, it will hold a paragraph. We’ll also add in a unique class to make it that much easier to target in our CSS.

With that, we’re already finished with the HTML. Though it’s not styled at all, the live preview perfectly showcases the hierarchy of our navigation menu. Here you can clearly see our menu beginning to take form.

screenshot

Base Styles

To start off our menu styling, we need to establish a few basics. First, we’ll clear the default margins and padding. We’ll be squishing the divs right up next to each other so any default browser spacing will ruin the layout.

Next, we’ll apply a simple color to the background so the white portions of our menu will stand out. Then we’ll toss in some basic font styles and add a slight shadow to the menu. Note that the margin set in the nav block centers the menu on the page, this is for display purposes only and should be removed when you want to nudge the menu into place.

Finally, we’ll add some dimensions and background color to the nav and menu-item selectors. Here’s the resulting code:

* {
  margin: 0px;
  padding: 0px;
}

body {
  background: #e5e5e7;
}

nav {
  font-family: Helvetica, Arial, "Lucida Grande", sans-serif;
  line-height: 1.5;
  margin: 50px auto; /*for display only*/
  width: 200px;
  -webkit-box-shadow: 2px 2px 5px rgba(0,0,0,0.2);
     -moz-box-shadow: 2px 2px 5px rgba(0,0,0,0.2);
          box-shadow: 2px 2px 5px rgba(0,0,0,0.2);
}

.menu-item {
  background: #fff;
  width: 200px; 
}

A this point, the preview is looking like we’ve done more harm than good, but fear not, it’ll start looking spiffy in no time.

screenshot

Header Styles

Now it’s time to style our h4 tags and turn them into the horizontal bars that we saw in our mockup. To do this, we just need a little padding and a background color. While we’re here we can begin to style the typography as well. We’re inheriting the font-family we set up before so we don’t need to re-type that. Instead we just need to set a size and weight.

/*Menu Header Styles*/
.menu-item h4 {
  color: #fff;
  font-size: 15px;
  font-weight: 500;
  padding: 7px 12px;
  background: #a90329;
}

As you can see in the image below, our link styles are still overriding some of the type styles we set here so we’ll need to go in and fix those next.

screenshot

Header Links

Obviously, the blue link is no good so we need to change that to white. We also want to ditch any text decoration (the underline). Now, we could stop here but the default behavior would be that only the text is clickable and not the whole bar, which is not ideal. To make the entire bar a link, we set the display property to block and the width to the full menu size (200px).

.menu-item h4 a {
  color: white;
  display: block;
  text-decoration: none;
  width: 200px;
}

Now our colored bar is looking much better. Here’s the preview:

screenshot

Making It Pretty

If you want to stick with something simple, you can skip this step, but I’m going to trudge on and add a few more visual tweaks. Go back and modify that header style block to include a gradient and some very subtle borders. You likely won’t even be able to spot the borders until the menu is closed, but combined with the gradients they’ll really help differentiate each section so they don’t all look like one big block.

/*Menu Header Styles*/
.menu-item h4 {
  border-bottom: 1px solid rgba(0,0,0,0.3);
  border-top: 1px solid rgba(255,255,255,0.2);
  color: #fff;
  font-size: 15px;
  font-weight: 500;
  padding: 7px 12px;
  
  /*Gradient*/
  background: #a90329; /* Old browsers */
  background: -moz-linear-gradient(top, #a90329 0%, #8f0222 44%, #6d0019 100%); /* FF3.6+ */
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#a90329), color-stop(44%,#8f0222), color-stop(100%,#6d0019)); /* Chrome,Safari4+ */
  background: -webkit-linear-gradient(top, #a90329 0%,#8f0222 44%,#6d0019 100%); /* Chrome10+,Safari5.1+ */
  background: -o-linear-gradient(top, #a90329 0%,#8f0222 44%,#6d0019 100%); /* Opera 11.10+ */
  background: -ms-linear-gradient(top, #a90329 0%,#8f0222 44%,#6d0019 100%); /* IE10+ */
  background: linear-gradient(top, #a90329 0%,#8f0222 44%,#6d0019 100%); /* W3C */
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#a90329', endColorstr='#6d0019',GradientType=0 ); /* IE6-9 */
}

screenshot

Hover Styles

Next we’re going to add a subtle hover style to the bar links. All we’re going to do is tweak the colors on the gradient a little so they get brighter when you hover.

.menu-item h4:hover {  
  background: #cc002c; /* Old browsers */
  background: -moz-linear-gradient(top,  #cc002c 0%, #6d0019 100%); /* FF3.6+ */
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#cc002c), color-stop(100%,#6d0019)); /* Chrome,Safari4+ */
  background: -webkit-linear-gradient(top,  #cc002c 0%,#6d0019 100%); /* Chrome10+,Safari5.1+ */
  background: -o-linear-gradient(top,  #cc002c 0%,#6d0019 100%); /* Opera 11.10+ */
  background: -ms-linear-gradient(top,  #cc002c 0%,#6d0019 100%); /* IE10+ */
  background: linear-gradient(top,  #cc002c 0%,#6d0019 100%); /* W3C */
  filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#cc002c', endColorstr='#6d0019',GradientType=0 ); /* IE6-9 */
}

screenshot

Paragraph Styles

Remember that the first item in our menu holds a paragraph and not an unordered list, so next we’ll attack this to get it looking nice. The lists will take a sizable chunk of code but the paragraph hardly requires anything. Just define the size and color, then toss in some padding.

/*First Item Styles*/
.alpha p {
	font-size: 13px;
	padding: 8px 12px;
	color: #aaa;
}

The top section is now looking great! Both the header bar and the paragraph are exactly where we need them to be.

screenshot

Unordered List Styles

There’s a ton of stuff that we need to do to get these lists straightened out. Let’s switch things up a bit and look at the code first, then I’ll walk you through it.

/*ul Styles*/
.menu-item ul {
  background: #fff;
  font-size: 13px;
  line-height: 30px;
  list-style-type: none;
  overflow: hidden;
  padding: 0px;
}

.menu-item ul a {
  margin-left: 20px;
  text-decoration: none;
  color: #aaa;
  display: block;
  width: 200px;
}

/*li Styles*/
.menu-item li {
  border-bottom: 1px solid #eee;
}

.menu-item li:hover {
  background: #eee;
}

As you can see, the first block targets the unordered list as a whole unit. Here I set some basic sizing and font styles and removed the bullet point by setting list-style-type to none.

Next I targeted the links specifically. I moved them over, removed the underlines, set the color and performed the same display:block trick that we saw before to make the clickable area larger.

To finish things off, I applied a few custom styles to the list items themselves. The bottom border creates a separation between each item and the hover style changes the background. Here’s the result of our labor, our menu is almost finished!

screenshot

Collapse And Animate

Up to this point, we’ve kept our menu opened up so that we could see it while we style the elements within. Now that we know that all of our visual styles are exactly like we want them, it’s time to collapse each section and then set them up to pop open on hover.

By default, browsers will set the height of those unordered lists to auto, meaning they’ll be just tall enough to hold all of the content within. To collapse the menu sections so that only the bars show, we can target those unordered lists and set the height to 0. Notice that we’re leaving the paragraph alone, this will ensure that our top section is always open.

/*ul Styles*/
.menu-item ul {
  background: #fff;
  font-size: 13px;
  line-height: 30px;
  height: 0px; /*Collapses the menu*/
  list-style-type: none;
  overflow: hidden;
  padding: 0px;
}

Now our menu is much shorter and doesn’t eat up so much space. You can also finally see the benefit of those gradients and borders that we implemented before.

screenshot

Animating the Transition

Next we’ll want to open these menus back up on hover, but before we do that, let’s set up an animation so the transition is nice and gradual. Make sure you insert the various browser extensions and target the height property.

/*ul Styles*/
.menu-item ul {
  background: #fff;
  font-size: 13px;
  line-height: 30px;
  height: 0px;
  list-style-type: none;
  overflow: hidden;
  padding: 0px;
  
  /*Animation*/
  -webkit-transition: height 1s ease;
     -moz-transition: height 1s ease;
       -o-transition: height 1s ease;
      -ms-transition: height 1s ease;
          transition: height 1s ease;
}

Expanding on Hover

All that’s left to do now is make it so that when you hover, the ul expands. This is tricky though so be careful. Your instinct may be to do something like “ul:hover” but that’s not what we want. Instead, we want to make it so that you can hover anywhere in that menu item, either in the bar or the unordered list. However, the item that we want expanded is still only the ul. Here’s what our selector looks like:

.menu-item:hover ul {
  height: 93px;
}

Sometimes reading a selector backwards is helpful when trying to figure out what it does. This tells our browser to set a height of 93px to our unordered lists when a .menu-item is hovered over.

screenshot

One important thing to note here is that we can’t just set the height to auto because for some reason this disables the animation. If you don’t want the animation, a height of auto is much more flexible and allows you to vary the number of sub-menu items. If you want to do this with the animation, you’ll have to target the height for each individually.

See It In Action

Our menu is now complete. Be sure to kick the tires in the demo to see how it all works. I’ll also throw in a link to the completed code so you can have a look at it all together.

Demo: Launch Demo
See the Code: Check out the HTML and CSS on Tinkerbin

Conclusion

I hope you enjoyed this walkthrough of building an animated vertical navigation menu. In implementation, it’s very similar to the animated download buttons that we built the other day so you should really be getting the hang of hiding and showing content using pure CSS.

Look out for an even better version of this menu to pop up on our brand new sister site, Design Curate. You’ll find a ton of great freebies there that you can download and implement in your projects today.

Comments & Discussion

31 Comments

Comments & Discussion

31 Comments

  1. Christian says:

    Thanks for this tutorial! :)

  2. Alexey says:

    Something’s wrong with your site. Norton Internet Security gives me ‘Web Attack: Blackhole Toolkit Website 12′ warning.

    http://designshack.net/js/designshack.js file is infected.

  3. Christen Bouffard says:

    A malware warning popped up for me too. I got a Google service notice warning me that this site had a potential for infecting my computer.

  4. Janos Maczko says:

    Hi, very useful article, thanks.
    Google malware warning popped…

  5. Camel says:

    These are amazing. I’m just learning how to do make some more advanced artwork.
    Thanks for sharing these.

  6. Arnaud says:

    I’ve been using similar menu (http://www.bealondoner.com/en/jobs) but without UL. The menu has been working fine so far on all platforms I tested it. All the menu will be display if you disable JS (it’s important to see how google will see the menu) and also how the site will behave with JS disable.

  7. SandpaperFinish says:

    Looks great. Works great. And no scripting, just CSS. Unfortunately, I was hoping the script-free approach would result in a very smooth mobile experience. Alas, it’s pretty choppy on my 4G phone (multi-core).

  8. Aleks says:

    Thanks, this is great!
    Anyone know how to make the menu work on mouse click instead on hover?

  9. rahul says:

    this is very use full.
    but i need not close the clike ul .

    thanks to help.

  10. Abicus says:

    Is there a fix for a smoother transition effect in IE? it looks like crap. In Firefox, it’s working like a charm!…Damn you IE! Please help!

  11. AndresH says:

    Hi, thanks for sharing. Any recommendation for making one of these menus with 4 items instead of 3, and still having the others with 3 ? Seems to be fixed in 3.

    Cheers.

  12. Ian says:

    Hi, Thanks for this! I was looking for exactly something like this to cut down on jquery for mobile apps where page load time is super important. I’m pretty sure a minimal pure javascript can be used to make this clickable instead of using hover and it will take way less download size than adding jquery just for this.

    • Josh says:

      Yeah, I am basing a webapp off this and javascript onclick is working well. I’d just like to find a way to get the height of a div if set to auto so I can vary the number of sub links without having to code the new height in… any ideas?

  13. Amanda says:

    I also am having problems with how many items I can display. I have 4 main categories and 8 sub-categories but only 4 are showing up. Any thoughts? Otherwise, love this!

  14. Sean says:

    Is there a way to do this without setting the overall padding and margin settings to 0? When I do that it messes up the format of the rest of my text.

  15. Sean says:

    never mind my last post. changing the h4 margin to 0 eliminates the need to change the overall margin

  16. Alan Gandy says:

    I did a workaround for the number of menu items.

    Edit the height value as a multiple of 31.
    .menu-item:hover ul {
    height: 62px;
    However, this still limits you to the same number of list items for each hover.

  17. Joseph Abankwa says:

    Hi is there a way to have more than 3 li items please, i’ll like to add more than one sub-catergory. Thanks

  18. Aaron says:

    Having a problem and it would be great if someone could help me out.
    http://img19.imageshack.us/img19/8326/extraspace.png

    Something is making extra space in between the panels and I can’t figure out what.

    I am pretty new with css, I added the css provided onto my own, http://tinkerbin.com/SAprhnW6

    The nav-bar is a copy/paste of the nav-bar provided in the download.

    My best guess is that css are conflicting to create padding but I am not sure.

    Thanks for the help ahead of time =)

  19. THANK YOU VERY MUCH GOOD SIR!

  20. Miguel Constanzo says:

    Great stuff!

    Any fix for IE?

    Note: If you have any trouble with the number of elements that you can see..this is controled by the following css line:

    .menu-item:hover ul {height: ?px;}

    just try increasing the number of pixels.

  21. Claire says:

    To fix the gaps between that Aaron was having add

    .menu-item ul { margin-top:0; margin-bottom: 0; }

    Works on Chrome, Safari and Firefox. Not tested in IE yet.

  22. nastik says:

    Superb Navigation and easy to use Thanks

  23. Ashraff says:

    Wow, great tutorial, thanks a lot dude.

  24. Bob Thompson says:

    This is how I fixed the different number of menu items in each .

    In the I added id=”menu-item-3″
    The 3 being the number of sub items or ‘s.
    If you have 5 items, the code would be id=”menu-item-5″

    e.g.

    Portfolio

    Web
    Print
    Other

    Then in the CSS replace

    .menu-item:hover ul {
    height: 93px;
    }

    with

    /*This is the distance the sub menu opens*/
    #menu-item-1:hover ul {
    height: 33px;
    }
    #menu-item-2:hover ul {
    height: 63px;
    }
    #menu-item-3:hover ul {
    height: 93px;
    }
    #menu-item-4:hover ul {
    height: 123px;
    }
    #menu-item-5:hover ul {
    height: 153px;
    }
    #menu-item-6:hover ul {
    height: 183px;
    }

    Works fine in the major browsers and my iPad.

    Hope this helps.

  25. Bob Thompson says:

    Correction to previous post.
    The div and li tags disappeared

    This is how I fixed the different number of menu items in each .

    In the div I added id=”menu-item-3″
    The 3 being the number of sub items or li‘s.
    If you have 5 items, the code would be id=”menu-item-5″

    e.g.

    div class=”menu-item” id=”menu-item-3″

    Then in the CSS replace

    .menu-item:hover ul {
    height: 93px;
    }

    with

    /*This is the distance the sub menu opens*/
    #menu-item-1:hover ul {
    height: 33px;
    }
    #menu-item-2:hover ul {
    height: 63px;
    }
    #menu-item-3:hover ul {
    height: 93px;
    }
    #menu-item-4:hover ul {
    height: 123px;
    }
    #menu-item-5:hover ul {
    height: 153px;
    }
    #menu-item-6:hover ul {
    height: 183px;
    }

    Works fine in the major browsers and my iPad.

    Hope this helps.

  26. shadowfox476 says:

    Thank you so much! This was very informative and helpful. Exactly what I needed.

  27. Mary Anne Wentink says:

    I’m new to CSS. I’ve been developing .asp/.aspx pages for year. Trying to integrate your dropdown got no further than the section where you began with a “*”. My page is showing the code as text. Can this be used with .asp/.aspx?

Leave a Comment

Subscribe
Membership
About the Author