Advertisement

Orman Clark's Vertical Navigation Menu: The CSS3 Version

by
This post is part of a series called Bringing Premium Pixels to Life.
Orman Clark's Chunky 3D Web Buttons: The CSS3 Version
Quick Tip: Give Orman's Navigation the :target Treatment

Next in the Orman Clark's coded PSD series is his awesome looking Vertical Navigation Menu. We'll recreate it with CSS3 and jQuery while using the minimal amount of images possible.

The only images we'll be using are for the icons - I'll be creating a sprite using a new tool called SpriteRight, but this is optional. Additionally, I'll be using GradientApp to create my CSS3 gradients, but again this is optional.


Step 1: Basic HTML Markup

Let's start off by throwing in some basic markup, an empty HTML5 document:

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8">
		
		<title>Vertical Navigation Menu: CSS3 Coded</title>
		
		<link rel="stylesheet" href="css/styles.css">
		
	</head>
<body>

</body>
</html>

And now the markup for our menu; an unordered list within a containing wrapper.

<div id="wrapper">

	<ul class="menu">
		<li class="item1"><a href="#">Friends <span>340</span></a></li>
		<li class="item2"><a href="#">Videos <span>147</span></a></li>
		<li class="item3"><a href="#">Galleries <span>340</span></a></li>
		<li class="item4"><a href="#">Podcasts <span>222</span></a></li>
		<li class="item5"><a href="#">Robots <span>16</span></a></li>
	</ul>

</div>

Lastly, we create the submenus by placing an unordered list nested within each of our existing list items.

<div id="wrapper">

	<ul class="menu">
		<li class="item1"><a href="#">Friends <span>340</span></a>
			<ul>
				<li class="subitem1"><a href="#">Cute Kittens <span>14</span></a></li>
				<li class="subitem2"><a href="#">Strange “Stuff” <span>6</span></a></li>
				<li class="subitem3"><a href="#">Automatic Fails <span>2</span></a></li>
			</ul>
		</li>
		<li class="item2"><a href="#">Videos <span>147</span></a>
			<ul>
				<li class="subitem1"><a href="#">Cute Kittens <span>14</span></a></li>
				<li class="subitem2"><a href="#">Strange “Stuff” <span>6</span></a></li>
				<li class="subitem3"><a href="#">Automatic Fails <span>2</span></a></li>
			</ul>
		</li>
		<li class="item3"><a href="#">Galleries <span>340</span></a>
			<ul>
				<li class="subitem1"><a href="#">Cute Kittens <span>14</span></a></li>
				<li class="subitem2"><a href="#">Strange “Stuff” <span>6</span></a></li>
				<li class="subitem3"><a href="#">Automatic Fails <span>2</span></a></li>
			</ul>
		</li>
		<li class="item4"><a href="#">Podcasts <span>222</span></a>
			<ul>
				<li class="subitem1"><a href="#">Cute Kittens <span>14</span></a></li>
				<li class="subitem2"><a href="#">Strange “Stuff” <span>6</span></a></li>
				<li class="subitem3"><a href="#">Automatic Fails <span>2</span></a></li>
			</ul>
		</li>
		<li class="item5"><a href="#">Robots <span>16</span></a>
			<ul>
				<li class="subitem1"><a href="#">Cute Kittens <span>14</span></a></li>
				<li class="subitem2"><a href="#">Strange “Stuff” <span>6</span></a></li>
				<li class="subitem3"><a href="#">Automatic Fails <span>2</span></a></li>
			</ul>
		</li>
	</ul>

</div>

Okay, there may seem a lot there but don't let it confuse you. First we've created an unordered list with five list items, each with an anchor tag inside. Then we've added nested unordered lists, each with three list items.

I've also added a class to each list item, just so it'll make styling easier later on. Finally, for the numbers we've created a span tag inside each anchor tag. If you view it in your browser it should look like this:

Basic markup

Step 2: Fluid Fonts

We'll first make sure our menu displays correctly. Add these rules to css/styles.css, they'll set the margin and padding of all our uls to 0, and remove the list style.

ul,
ul ul {
	margin: 0;
	padding: 0;
	list-style: none;
}

Before we start styling our menu we'll create a wrapper with a fixed width and a font-size of 13px (expressed in em units). Firstly we'll add a rule to the body, font-size:100%;. This will ensure that our styling is based on the browser default font-size (usually 16px).

Now to explain how the wrapper font size works. We have to express it as an em; proportional to the size of its parent's font-size. We're aiming for 13px, so assuming the parent size is 16px, our resultant em is 13 / 16 = 0.8125. 13px is 0.8125*16px.

Measuring our fonts (and other elements) in em units will make them fluid. Now if we change the wrapper font size (or our browser default size) the whole menu will adjust in relation to that base. Try not to let this confuse you, if you need help with converting your fonts I suggest you visit pxtoem.com.

body {
	font-size: 100%;
}
a {
	text-decoration: none;
}
ul, 
ul ul {
	margin: 0;
	padding: 0;
	list-style: none;
}
#wrapper {	
	width: 220px;
	margin: 100px auto;
	font-size: 0.8125em;
}

We've given the wrapper a fixed width of 220px and centered it with some margin top by adding margin:100px auto;.


Step 3: Main Menu CSS

Next we'll add some styling for the menu. We'll make the width and height of the menu ul auto, then apply a shadow to the whole thing. By adding the height as auto, the shadow will adjust when the slider opens.

Then the anchor tags; we'll add a width of 100% which means they will stretch to the 220px width of the wrapper. For a height we'll use ems, so think back to our main font-size of 13px. Our .psd shows a height of 36px, so that's our target. We'll take 36 and divide it by 13 which comes out to roughly 2.75em (36 / 13 = 2.76923077). We'll also use 2.75em for the line height (to center all text vertically) then apply some text-indent to push text in, making space for our icon later on.

We'll add a CSS3 gradient for the background, I went ahead and created this with GradientApp. Next we'll change the font, we'll apply the Helvetica Neue font and a white color along with a text shadow. Note we didn't use a font-size here. That's because our base font is 13px for the wrapper which our anchors have inherited, so no need to add it in.

body {
	font-size: 100%;
}
a {
	text-decoration: none;
}
ul, 
ul ul {
	margin: 0;
	padding: 0;
	list-style: none;
}
#wrapper {	
	width: 220px;
	margin: 100px auto;
	font-size: 0.8125em;
}
.menu {
	width: auto;
	height: auto;
	-webkit-box-shadow: 0px 1px 3px 0px rgba(0,0,0,.73), 0px 0px 18px 0px rgba(0,0,0,.13);
	-moz-box-shadow: 0px 1px 3px 0px rgba(0,0,0,.73), 0px 0px 18px 0px rgba(0,0,0,.13);
	box-shadow: 0px 1px 3px 0px rgba(0,0,0,.73), 0px 0px 18px 0px rgba(0,0,0,.13);
}
.menu > li > a {
	background-color: #616975;
	background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(114, 122, 134)),to(rgb(80, 88, 100)));
	background-image: -webkit-linear-gradient(top, rgb(114, 122, 134), rgb(80, 88, 100));
	background-image: -moz-linear-gradient(top, rgb(114, 122, 134), rgb(80, 88, 100));
	background-image: -o-linear-gradient(top, rgb(114, 122, 134), rgb(80, 88, 100));
	background-image: -ms-linear-gradient(top, rgb(114, 122, 134), rgb(80, 88, 100));
	background-image: linear-gradient(top, rgb(114, 122, 134), rgb(80, 88, 100));
	filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#727a86', EndColorStr='#505864');
	border-bottom: 1px solid #33373d;
	-webkit-box-shadow: inset 0px 1px 0px 0px #878e98;
	-moz-box-shadow: inset 0px 1px 0px 0px #878e98;
	box-shadow: inset 0px 1px 0px 0px #878e98;
	width: 100%;
	height: 2.75em;
	line-height: 2.75em;
	text-indent: 2.75em;
	display: block;
	position: relative;
	font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
	font-weight: 600;
	color: #fff;
	text-shadow: 0px 1px 0px rgba(0,0,0,.5);
}

Okay! Now it's starting to look better and we're getting some structure too! But how about we add a background color so the menu will stand out better..

body {
	background:#32373d;
}
Step 2

Tip: Remembering EMs

From the CSS above you can see that it's easy to forget what your em units actually mean. It's a good idea to leave comments of your original calculations, so that when you come back to your code in the future you can still decipher what's going on. Remember the formula: desired px / parent px = resultant em and use the approximate symbol (≈) if you're rounding the result.

#wrapper {	
	font-size: 0.8125em; 	/* 13/16 = 0.8125*/
}

.menu > li > a {
	height: 2.75em;			/* 36/13 ≈ 2.75*/
	line-height: 2.75em;	/* 36/13 ≈ 2.75*/
	text-indent: 2.75em;	/* 36/13 ≈ 2.75*/
}

Step 4: Sub Menu CSS

Time to add some CSS for the white sub menus. We'll need to add a white background with some gray borders. Notice for the last one it doesn't have a bottom border, so we'll target it with the :last-child pseudo selector to remove it. It does have a dark blue border so we'll remove the gray one, adding a blue one.

The next step will be similar to the previous; we'll add the heights and widths again, we'll change the background to white. This time we need to change the font size. We're aiming for 12px so using our calculation of desired px / parent px = resultant em we get 0.923em

Let's also change the text color to a gray. Note we used display:block. If we'd used float:left the menus wouldn't smoothly animate, so we use display block to help them move nice and smoothly. you'll also notice we've added an extra style; we're applying this to the last child of the sub-ul. We need to do this so we're able to change the border color.

.menu ul li a {
	background: #fff;
	border-bottom: 1px solid #efeff0;
	width: 100%;
	height: 2.75em;
	line-height: 2.75em;
	text-indent: 2.75em;
	display: block;
	position: relative;
	font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
	font-size: 0.923em;
	font-weight: 400;
	color: #878d95;
}
.menu ul li:last-child a {
	border-bottom: 1px solid #33373d;
}

It's starting to look really good now!

Step 3

Step 5: Hover and Active Styling

We'll add some hover and active styles now, especially for when the accordion is open! We'll also add a border bottom to the active menu. Now if you're thinking, "why haven't we added an active class?". Well my friend, that's what the jQuery will be doing later on.

.menu > li > a:hover, 
.menu > li > a.active {
	background-color: #35afe3;
	background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(69, 199, 235)),to(rgb(38, 152, 219)));
	background-image: -webkit-linear-gradient(top, rgb(69, 199, 235), rgb(38, 152, 219));
	background-image: -moz-linear-gradient(top, rgb(69, 199, 235), rgb(38, 152, 219));
	background-image: -o-linear-gradient(top, rgb(69, 199, 235), rgb(38, 152, 219));
	background-image: -ms-linear-gradient(top, rgb(69, 199, 235), rgb(38, 152, 219));
	background-image: linear-gradient(top, rgb(69, 199, 235), rgb(38, 152, 219));
	filter: progid:DXImageTransform.Microsoft.gradient(GradientType=0,StartColorStr='#45c7eb', EndColorStr='#2698db');
	border-bottom: 1px solid #103c56;
	-webkit-box-shadow: inset 0px 1px 0px 0px #6ad2ef;
	-moz-box-shadow: inset 0px 1px 0px 0px #6ad2ef;
	box-shadow: inset 0px 1px 0px 0px #6ad2ef;
}
.menu > li > a.active {
	border-bottom: 1px solid #1a638f;
}

Step 6: Main Menu Icons

We'll add the icons using the :before pseudo. First we'll target all the sub-ul anchor tags, we'll apply the background sprite and set it to no repeat. We'll give it a font size of 36px although there is no text; we'll use 36px so we can use a width and height of 1em which will now equal 36px. We'll then push the element down 50% and remove .5em off the margin top to center it.

Using the classes for each sub-ul list item, we'll target them and give them each the appropriate background position for the sprite.

Note: I created this sprite using the new app called SpriteRight, if you wish to fiddle around with the sprite, I've included the images and project files in the source files.

.menu > li > a:before {
	content: '';
	background-image: url(../images/sprite.png);
	background-repeat: no-repeat;
	font-size: 36px;
	height: 1em;
  	width: 1em;
	position: absolute;
  	left: 0;
	top: 50%;
	margin: -.5em 0 0 0;
}
.item1 > a:before {
	background-position: 0 0;
}
.item2 > a:before {
	background-position: -38px 0;
}
.item3 > a:before {
	background-position: 0 -38px;
}
.item4 > a:before {
	background-position: -38px -38px;
}
.item5 > a:before {
	background-position: -76px 0;
}
Step 5

Step 7: Main Menu Numbers

Okay, remember those spans we added? These will create the numbers!

First we'll add a font-size of 11px (which converts to roughly 0.857em). We'll position them absolutely, and push them from the right by 1em, once again - em to make this fluid. We'll push it down 50% from the top and remove the margin-top to center it. A background will be added along with some box shadows, an inset and outset one.

Once again to make it fluid, we'll use padding to create the width and height. We've even used ems on the border radius; we'll need this because if the text is made bigger they'll appear disproportionate. I've also added another style for when hovering or an active class is applied to the link.

.menu > li > a span {
	font-size: 0.857em; 
	display: inline-block;
	position: absolute;
	right: 1em;
	top: 50%; 
	background: #48515c;
	line-height: 1em;
	height: 1em;
	padding: .4em .6em;
	margin: -.8em 0 0 0; 
	color: #fff;
	text-indent: 0;
	text-align: center;
	-webkit-border-radius: .769em;
	-moz-border-radius: .769em;
	border-radius: .769em;
	-webkit-box-shadow: inset 0px 1px 3px 0px rgba(0, 0, 0, .26), 0px 1px 0px 0px rgba(255, 255, 255, .15);
	-moz-box-shadow: inset 0px 1px 3px 0px rgba(0, 0, 0, .26), 0px 1px 0px 0px rgba(255, 255, 255, .15);
	box-shadow: inset 0px 1px 3px 0px rgba(0, 0, 0, .26), 0px 1px 0px 0px rgba(255, 255, 255, .15);
	text-shadow: 0px 1px 0px rgba(0,0,0,.5);
	font-weight: 500;
}
.menu > li > a:hover span, .menu > li a.active span {
	background: #2173a1;
}
Step 6

Step 8: Sub Menu Numbers and Arrow

This process will be similar to the previous step so I won't go into much detail. The main differences here are that I've removed the background color, changed the border and changed the font color. We also need to add that arrow and will once again lean on the :before psuedo. We define a width and height and add some left positioning using ems to ensure it is fluid.

Lastly, a hover state (thanks to those in the comments who pointed out its initial absence). We simply apply a darker color (#32373D) to the anchor text, the pseudo arrow and the number within the span.

.menu ul > li > a span {
	font-size: 0.857em; 
	display: inline-block;
	position: absolute;
	right: 1em;
	top: 50%; /
	background: #fff;
	border: 1px solid #d0d0d3;
	line-height: 1em;
	height: 1em;
	padding: .4em .7em;
	margin: -.9em 0 0 0; 
	color: #878d95;
	text-indent: 0;
	text-align: center;
	-webkit-border-radius: .769em;
	-moz-border-radius: 769em;
	border-radius: 769em;
	text-shadow: 0px 0px 0px rgba(255,255,255,.01));
}
.menu > li > ul li a:before {
	content: '▶';
	font-size: 8px;
	color: #bcbcbf;
	position: absolute;
	width: 1em;
	height: 1em;
	top: 0;
	left: -2.7em;
}

.menu > li > ul li:hover a,
.menu > li > ul li:hover a span,
.menu > li > ul li:hover a:before {
	color: #32373D;
}

So it's looking pretty cool now right? I think it's time we added some functionality to this!

Step 7

Step 9: jQuery Time

Bet you've been waiting to get here?! Well we're finally at the jQuery point. We'll first need to link to the jQuery library, using one hosted by Google. The current latest version is 1.7.1. Add the following to the head section of your HTML page:

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>

Now add the following to the bottom of your html document, before the closing </body> tag. Don't worry if this looks too confusing, I'll explain it in a minute.

<script type="text/javascript">
$(function() {

    var menu_ul = $('.menu > li > ul'),
        menu_a  = $('.menu > li > a');
    
    menu_ul.hide();

    menu_a.click(function(e) {
        e.preventDefault();
        if(!$(this).hasClass('active')) {
            menu_a.removeClass('active');
            menu_ul.filter(':visible').slideUp('normal');
            $(this).addClass('active').next().stop(true,true).slideDown('normal');
        } else {
            $(this).removeClass('active');
            $(this).next().stop(true,true).slideUp('normal');
        }
    });

});
</script>
    var menu_ul = $('.menu > li > ul'),
        menu_a  = $('.menu > li > a');

First we're storing the sub-menu and the main menu anchor tags in two different variables, this just makes it easy to refer to them later on.

	    
    menu_ul.hide();

This will hide all the sub-menus when the page loads

	    
    menu_a.click(function(e) {

First we will tell it to do something when we click one of the main menu's anchor tags.

	    
        e.preventDefault();

Here we're preventing the anchor tags from following any links or changing the address in the address bar. e.g. if you ever create an anchor tag with a link of '#', when you click it, it will not show up in the address bar now. The anchor tags are basically disabled.

	    
        if(!$(this).hasClass('active')) {
            menu_a.removeClass('active');

Now we'll instruct it that IF the menu_a has the class 'active', remove it.

	    
            menu_ul.filter(':visible').slideUp('normal');

Here we use '.filter' and ':visible'. If a menu is open, slide it up with a speed of normal.

	    
            $(this).addClass('active').next().stop(true,true).slideDown('normal');

If the menu is closed, add the class 'active' (so we can access the nice CSS style) and slide it down with a speed of normal.

	    
        } else {
            $(this).removeClass('active');
            $(this).next().stop(true,true).slideUp('normal');

Now, we'll need to use an ELSE as part of our conditional statement. So, ELSE remove the class active, and slide the menu up to hide it. This is just so we can code any menu without having to reload the page.

Note: If you'd like to change the speed of slide, change normal to, e.g. '500'. That will slide it at 500 milliseconds.

If you're interested in learning jQuery from scratch, you'd be well advised to check out the free Learn jQuery in 30 Days course from tutsplus.com.


Conclusion

Well we made it to the end! We've coded up Orman's beautiful vertical navigation menu using CSS3 and jQuery! Stay tuned for a quick tip on how to create this using only CSS3 with the :target pseudo selector.

Final
Final large
#wrapper {width: 440px; font-size: 1em}

I hope you enjoyed this tutorial, thanks for reading!