Navigation

Create a stunning menu in CSS3

CSS, Web Design | Aug 3, 2012

The advent of CSS3 has introduced a world of possibilities for web designers and developers. With animations, shadows, rounded corners and more, elements can be easily styled, and still weigh less than ever before.

The navigation of a website is one of the most fundamental aspects to make or break a user’s experience. Instead of loading your menu down with individual images or sprites, why not do the entire thing in CSS3?

No need for jQuery or JavaScript; no need to launch Photoshop. And let’s take it up a notch by including a great icon font to add some character to our menu.

So grab your favorite cup of coffee (or if you’re like me, an ice cold Diet Coke), open up your favorite code editor, and let’s make a slick navigation menu using only CSS3.

 

Before we get started

Before we dive into the code for our menu, I’d like to go over some of the assets and tools we’ll use in this tutorial, which you can download and use while you follow along. These are all included in the .zip file at the end, which also includes the final code.

Alright, got all those? Or at least downloaded them with the full .zip file? Great, now let’s get started. We’ll walk through the set up in pieces, starting with the HTML, then the basic CSS, and finally spicing it up with CSS3.

 

The HTML

Since we’re being progressive with CSS3 in our menu system, I went ahead and set us up with a very basic HTML5 setup. No need to go crazy here – we’re not building out an entire site in this tutorial, just the menu.

Let’s jump in to the code for the menu. The menu is just a simple unordered list, with nested lists for drop downs. The unordered list is wrapped in an HTML5 tag.

As you can see, we’ve got five menu items, four of which have sub-items. The next step is to get the basic CSS styling done, then we’ll apply the CSS3 to the menu, and the spans to achieve the icons.

 

The CSS

To get a good baseline to work with, we’ll add the denim pattern from Subtle Patterns and center the menu, based on a 960.gs grid. We’ll also create a clearfix class, which is used in our menu systems.

/* http://meyerweb.com/eric/tools/css/reset/
   v2.0 | 20110126
   License: none (public domain)
*/

html, body, div, span, applet, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
a, abbr, acronym, address, big, cite, code,
del, dfn, em, img, ins, kbd, q, s, samp,
small, strike, strong, sub, sup, tt, var,
b, u, i, center,
dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, embed,
figure, figcaption, footer, header, hgroup,
menu, nav, output, ruby, section, summary,
time, mark, audio, video {
	margin: 0;
	padding: 0;
	border: 0;
	font-size: 100%;
	font: inherit;
	vertical-align: baseline;
}
/* HTML5 display-role reset for older browsers */
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
	display: block;
}
body {
	line-height: 1;
}
ol, ul {
	list-style: none;
}
blockquote, q {
	quotes: none;
}
blockquote:before, blockquote:after,
q:before, q:after {
	content: '';
	content: none;
}
table {
	border-collapse: collapse;
	border-spacing: 0;
}
body {
    background: url('img/denim.png');
    font-family: 'Droid Sans', sans-serif;;
}

.clearfix {
    clear: both;
}

.wrap {
    width: 940px;
    margin: 4em auto;
}

Now, we’ll get to work on styling the menu. First, we style the top level navigation to create a very basic framework.

nav {
    padding: 0 10px;
    position: relative;
}
.menu li {
    float: left;
    position: relative;
}
.menu li a {
    color: #444;
    display: block;
    font-size: 14px;
    line-height: 20px;
    padding: 6px 12px;
    margin: 8px 8px;
    vertical-align: middle;
    text-decoration: none;
}
.menu li a:hover {
    color: #222;
}
Step 1

Let’s walk through that code. The menu bar is going to span the full width of the .wrap class, which is 940 pixels. To add a bit of whitespace for the first menu item, we add 10 pixels of padding on the left and right side, and set the position of the nav bar to relative. This becomes a very important declaration later. The top level menu items are floated left, and also have a relative positioning. Then we take a step further and style the links, which are set to display: block;. This is different from several CSS menu systems out there which have display: inline; declared.

 

The Dropdown

The dropdown menus are nested unordered lists, so let’s style them next. Again, we’re going with the basic CSS here.

/* Dropdown styles */
.menu ul {
    position: absolute;
    left: -9999px;
    list-style: none;
}
.menu ul li {
    float: none;
}
.menu ul a {
    white-space: nowrap;
}
/* Displays the dropdown on hover and moves back into position */
.menu li:hover ul {
    left: 5px;
}
/* Persistent Hover State */
.menu li:hover a {
    color: #222;
}
.menu li:hover ul a {
    background: none;
}
.menu li:hover ul li a:hover {

}
Step 2

What? Where’d our menu go? Remember, this is a work in progress. It will start to come together, I promise. The .menu ul sets the position to absolute (remember, this unordered list is inside the top level list item, which is positioned relatively — thus, the .menu ul is positioned relatively to the top level list item). Then, we position it way off screen. This is a technique I picked up from CSSWizardy, as this method provides better accessibility for screen readers, etc. Later, we’ll call it back on our hover states.

Next, we set the drop down list items to float left, creating a uniform look for the drop down item. On the anchor tag, we throw in a whitespace: nowrap; which prevents long links from wrapping on to two lines. This helps maintain a uniform look and keeps the user interface easy to use.

Moving on to the hover states, when hovering on the top level list item (.menu li) we throw on a hover and target our sub unordered lists, and move the list from way off screen to 5 pixels to the left of the list item. Again, the positioning is relative to the top level list item, so it is offset by 5 pixels from the list item. If you were to remove the relative position of the top level li, all of your hovers would fly out under the ‘Home’ link.

Now, we’ll make sure that when we’re hovering on our drop downs, the top level li maintains the styling, but, the drop down menu items don’t have that style. That is where your .menu li:hover a and .menu li:hover ul a come into play. The former sets the persistent hover state (so make this the same as your top level style), and the latter removes that styling from the sub navigation lists.

Finally, we style the drop down menu items. Oh, it’s blank? Yeah, it’s all CSS3. We’ll get to that in a minute.

 

The CSS3

Now we get to the fun part. The CSS3 specification has introduced a lot of fun and exciting tools to web designers and developers utilizing modern web browsers. Sure, not all browsers support all of the CSS3 specs (check out css3files.com for a great primer on what works and what doesn’t), but many of the specifications degrade gracefully and do not break the design.

Note: for this tutorial, I’m using Lea Verou’s powerful and epically tiny (2kb) -prefix-free.js script. If you haven’t used it before and you work with CSS3, do yourself a favor and check it out. It uses some crazy advanced detection to take CSS3 declarations and add the appropriate vendor prefixes to ensure browser compatibility when needed. It keeps the code a lot cleaner and makes the tutorial easier to understand.

Let’s add some CSS3 to the navigation bar, the top level unordered list and list items.

nav {
    background: -webkit-gradient(linear, center top, center bottom, from(#fff), to(#ccc));
    background-image: linear-gradient(#fff, #ccc);
    border-radius: 6px;
    box-shadow: 0px 0px 4px 2px rgba(0,0,0,0.4);
    padding: 0 10px;
    position: relative;
}
.menu li a:hover {
    background: -webkit-gradient(linear, center top, center bottom, from(#ededed), to(#fff));
    background-image: linear-gradient(#ededed, #fff);
    border-radius: 12px;
    box-shadow: inset 0px 0px 1px 1px rgba(0,0,0,0.1);
    color: #222;
}
Step 3

First up in the above code is the navigation bar. We add a linear gradient from white to a light gray (using both the standard gradient declaration, and the old -webkit- style to maintain compatibility with older browsers. We round out (no pun intended) the nav bar with a 6 pixel border radius.

On to the hover states: we add an opposite linear gradient, as well as some rounded corners, and an inset box shadow, giving our links the appearance that the menu item drops into the nav bar. Overall, a very clean look. Before we get to the hover states, I want to revisit some of the HTML in connection with some CSS3. I used a great icon font called Iconic by Some Random Dude, which is embedded with the CSS3 @font-face property, and then called with span tags on the menu items. Once you download the set, you can snag the code from the CSS in the zip file, as well as copy over the font files. If you change the relative path, remember to change the src in the @font-face.

@font-face {
    font-family: 'IconicStroke';
    src: url("fonts/iconic/iconic_stroke.eot");
    src: local('IconicStroke'),
    url("fonts/iconic/iconic_stroke.svg#iconic") format('svg'),
    url("fonts/iconic/iconic_stroke.otf") format('opentype');
}
.iconic {
    color:inherit;
    font-family: "IconicStroke";
    font-size: 38px;
    line-height: 20px;
    vertical-align: middle;
}

With that font declaration, you can now style span tags with specific classes to create the icons. For my project, I keep iconic.css as a fully intact stylesheet named after my style.css. To incorporate the icons in my menus, we’ll alter the HTML slightly:

Obviously, the code above only updates the top level navigation, by adding a span tag with the class iconic and the appropriate icon class. So now that that is done, we’ll do the final styling of the drop down menu items, which throw in some new CSS3 properties like opacity and a transition. So first, the .menu ul:

.menu ul {
    position: absolute;
    left: -9999px;
    list-style: none;
    opacity: 0;
    transition: opacity 1s ease;
}

The two big properties to review here are the opacity and transition declarations. Opacity is set to 0, and the transition will make the drop down menu go from an opacity of 0 to an opacity of 1 over the course of 1 second. Now let’s do the hover state.

.menu li:hover ul {
    background: rgba(255,255,255,0.7);
    border-radius: 0 0 6px 6px;
    box-shadow: inset 0px 2px 4px rgba(0,0,0,0.4);
    left: 5px;
    opacity: 1;
}
Step 4

The hover state is a fairly complex one to think about. Let’s go line by line.

The top line makes the background a pure white background, then sets the opacity to 70% to let some of the background pattern peek through.

Secondly, I’ve rounded the bottom two corners, leaving the top corners squared off to give the allusion that the drop down is coming out from the nav bar.

But the third line is where the magic comes in. Due to the positioning of the navigation bar and list items, the use of z-index is virtually impossible for layering to get an appropriate affect. To achieve the appearance that the drop down is beneath the nav bar, we set a light, similar inset box-shadow that comes down into the drop down. Finally, set the opacity to 1, which coordinates to the transition we set earlier.

The rest of the CSS3 is pretty straight forward, and largely repetitive of what we’ve gone over already:

.menu li:hover a {
    background: -webkit-gradient(linear, center top, center bottom, from(#ccc), to(#ededed));
    background-image: linear-gradient(#ccc, #ededed);
    border-radius: 12px;
    box-shadow: inset 0px 0px 1px 1px rgba(0,0,0,0.1);
    color: #222;
}
.menu li:hover ul a {
    background: none;
    border-radius: 0;
    box-shadow: none;
}
.menu li:hover ul li a:hover {
    background: -webkit-gradient(linear, center top, center bottom, from(#eee), to(#fff));
    background-image: linear-gradient(#ededed, #fff);
    border-radius: 12px;
    box-shadow: inset 0px 0px 4px 2px rgba(0,0,0,0.3);
}

Shouldn’t be too much out of the ordinary in that last set of code. And take a look at our final result.

Step 5

 

Conclusion

Well there you have it; a slick and smooth CSS3 menu. I’ve included all of the assets in a zip file, which you can download here, or you can view the demo here.

What are your thoughts on a navigation menu using nothing but CSS? Is it a viable solution to any menus on your websites? Continue the discussion in the comments below.

Alex Ball is the web developer for the NHL’s Washington Capitals in Washington, D.C. A fan of the ever changing web, he is passionate about new web standards, CSS3, jQuery, Responsive Design and email marketing.

Share this post
Comments (no login required)
  • http://twitter.com/edimoldovan Eduárd Moldován

    Hey, the demo url is not working.

    • Walter

      Apologies Eduárd, the broken URLs were due to server migration. If you check you’ll find they’re working correctly now.

  • Hey

    No demo, no download. Both broken.

    • Walter

      Thanks for pointing this out.  This was due to server migration, if you check them now you’ll see they’re working.

  • Markus Schulz

    Nice use of CSS3.

    Just one thing about the html: i dont’t like the empty span for the icons.
    Possibly a better solution might be a :before pseudoclass with the content-attribute holding the icon-char…if you already use css3.

    Apart from that – nice job.

  • Jon

    The icon really needs centering vertically inside the indentation on hover – it’s too close to the top and it’s bugging me!

  • drx

    This blog series is seriously disappointing. The demos more often than not are missing or broken links. I don’t want to read about the implementation if I can’t try it first and see if it’s any better or just the same as 100 other poor implementations. Do us all a favor and do some quality checking before hitting the publish button.

    • Walter

      Sorry, about that. It was a temporary issue due to server migration, both URLs are working now.

  • Anon

    This one also does not work in IE, why create tutorials that are useless to developers? Or at least make a note that it will only work in newer browsers, and that some of that CSS could probably be replaced with a small reusable image and a little js could make this work across all browsers just fine. Sticking to CSS3 cuz “it’s the new and cool thing to do” makes as much sense as watching reality shows…

    • Scorpineo

      I’m using the latest IE and it looks….like crap in IE!

  • http://tierrepeterson.com/blog TrP

    I’m not criticizing the blog, b/c it’s a good source for me.  Thanks for everything.  I’d like to see the demo at the top of the article (once we get the links).  
    Nice article…

  • Guest

    Demo: http://netdna.webdesignerdepot.com/uploads7/create-a-stunning-menu-in-css3/demo/
    Archive: http://netdna.webdesignerdepot.com/uploads7/create-a-stunning-menu-in-css3/demo.zip

  • http://websourcefree.com/ saha

    Icons in the menu are stunning. Looking very elegant. Demo page is working fine. Thanks for sharing :)

  • http://twitter.com/lucky_javid Javid Hussain

    that was so nice …. 

  • http://www.blackbookoperations.com/ Black Book Operations

    Thanks for this, got it to work with some tweaking now, always good to see whats out there with css3

  • http://twitter.com/Flocke Jens Grochtdreis

    Please do yourself and your readers a favor and forget about “prefixfree”. This library is good for usage in presentation but not for production code. If you use it you will rely on JavaScript for your CSS3 to work. That’s not a good idea. If you are too lazy to write all the prefixes why not use a preporcessor like Sass or use snippets in your editor. 

    But please do not use prefixfree.

  • Jorge

    How can I make it work in IE?

  • Scorpineo

    The button labels on the main menu in the demo are not aligned properly?

  • Henry Gallegos

    Thx for sharing

  • Rui Alão

    In Chrome the text overlaps with the icons… Or is it just me?

  • http://www.jerufonseca.co.cc/ Jerusalem Fonseca

    Now this is an awesome menu