Code a Responsive Navigation Menu

by on 14th March 2012 with 38 Comments

screenshot

Navigation menus used to be a fairly simple thing. Code up an unordered list, float it left and you’re good to go. With responsive design being all the rage these days though you’re faced with some new challenges when creating a menu design.

Follow along as we start from scratch and code a simple but effective responsive navigation menu that you can easily modify and reuse in your own projects.

What We’re Building

If you’re the kind of person who likes to skip ahead, here’s a sneak peek at what we’re building. Be sure to resize your browser window to see the responsive concepts in action.

Demo: Click here to see and tweak it on Dabblet.

screenshot

The HTML

Let’s jump right into this project without a bunch of unnecessary fluff. I’m sure you’re eager to get to the good stuff.

The first step is to decide on some markup. Since this is a navigation menu, it’s the perfect place to implement the HTML5 “nav” element.


Believe it or not, this one little piece of code had my head spinning when it came time to test. For some reason unknown to me, my styles simply weren’t taking effect in IE6-8! After a good ten minutes of fumbling around, I slapped myself in the head as I realized that I had used HTML5 elements, which of course aren’t supported by anything older than IE9.

Fortunately, the fix is easy, just drop in the famous html5shiv and you’re good to go (place this in the head portion of your document).


Add the List

Now that we’ve got our container element figured out, it’s time to toss in a simple UL with eight links. This tutorial is pretty dependent on the number of links so be sure to use eight if you’re not confident enough to venture out on your own in some areas.

Add The Sub Tag

To make the menu a little more interesting and helpful, let’s include another line of text below the initial one on each of the menu items. There are a number of ways that we could go about this so feel free to disagree with how I approached it. Basically I just tossed in a break tag and used a small element for the second line. The second item will indeed be small so this gives us a fairly semantic hook without any unnecessary divs, IDs or classes.

Progress Check

After this step you should have a simple, unstyled list of links. Notice that without any effort, those small tags are already going to work and reducing the size of every other line.

screenshot

Starter Styles

To begin our CSS, let’s pull out that good old universal selector and take Paul Irish’s advice by applying box-sizing: border-box to every element. This will help us size things easily with percentages even though we’ll be using borders.

* {
	padding: 0;
	margin: 0;
	
	-webkit-box-sizing: border-box;
	   -moz-box-sizing: border-box;
	        box-sizing: border-box;
}

Container Styles

Before we get into styling the individual list elements, let’s apply some basic styling to our parent elements. First up, target the nav element and set it to 90% of the width of the body. This will stretch most of the way across the available space but still leave our nav a little room to breathe. Be sure to center it on the page as well with auto margins.

Also jump in and apply the necessary unordered list styles to reset the list and eliminate any bullets.

nav {
	width: 90%;
	margin: 50px auto;	
}

nav ul {
	list-style: none;
	overflow: hidden;
}

screenshot

Menu Styles

Now that our parent elements have their act together, it’s time to work specifically on the menu items, which can be targeted via the nav element in conjunction with the anchor tags and list items.

Here’s a big chunk of code but don’t be afraid of it, I’ll walk you through it piece by piece.

nav li a {
	background: #444;
	border-right: 1px solid #fff;
	color: #fff;
	display: block;
	float: left;
	font: 400 13px/1.4 'Cutive', Helvetica, Verdana, Arial, sans-serif;
	padding: 10px;
	text-align: center;
	text-decoration: none;
	text-transform: uppercase;
	width: 12.5%;
}

/*SMALL*/
nav small {
	color: #aaa;	
	font: 100 11px/1 Helvetica, Verdana, Arial, sans-serif;
	text-transform: none;
	
}

I’ve ordered the properties here alphabetically for easy reference but to be honest this isn’t really my preferred way to do things. I like to group styles by function so that they make a little more sense. If we reorder our styles this way, they become easier to discuss.

nav li a {
	display: block;
	float: left;
	width: 12.5%;
	padding: 10px;
	
	background: #444;
	border-right: 1px solid #fff;
	
	color: #fff;	
	font: 400 13px/1.4 'Cutive', Helvetica, Verdana, Arial, sans-serif;
	text-align: center;
	text-decoration: none;
	text-transform: uppercase;
}

First up is the chunk of styles that defines the shape and layout of each list item. We’ve changed the anchors to block level items, floated them to the left, assigned a width and given them a little padding. This will create a nice big rectangle for each link in the menu. Why 12.5% for the width? Because we have eight menu items and 100% / 8 gives us 12.5% width on each item.

Next up is the chunk of code that defines the visual styling of the boxes that we just created. We’ve given them a background color and a single pixel border on the right side.

Finally, we end with all of the styles that relate to the text of the menu. This is all pretty basic stuff, the one curve ball is the “Cutive” font, which you can find here.

For the small styles, I changed the color, removed the uppercase text-transformation and set the font to Helvetica.

Progress Check

These styles made all the difference in the world. Our menu is looking much better. The custom font is working, the links are inline, the small text is perfect; it’s a beautiful thing.

screenshot

Hover Styles

When the user hovers over a menu item, let’s take it all the way to black. To make it feel a little nicer, I added a half second transition as well.

nav li a {
	background: #444;
	border-right: 1px solid #fff;
	color: #fff;
	display: block;
	float: left;
	font: 400 13px/1.4 'Cutive', Helvetica, Verdana, Arial, sans-serif;
	padding: 10px;
	text-align: center;
	text-decoration: none;
	text-transform: uppercase;
	width: 12.5%;
	
	/*TRANSISTIONS*/
	-webkit-transition: background 0.5s ease;
	   -moz-transition: background 0.5s ease;
	     -o-transition: background 0.5s ease;
	    -ms-transition: background 0.5s ease;
	        transition: background 0.5s ease;
}

/*HOVER*/
nav li a:hover {
	background: #222;
}

screenshot

Border Fix

Now, you can’t see it given that our background is white, but there’s actually a problem with our borders. They’re really just meant to give a little bit of visual definition to each menu item, which means there’s no need for one at the very end. To fix this, we can use the last:child pseudo class.

nav li:last-child a {
	border: none;
}

Below I’ve applied a temporary background color just so you can see the difference between the before and after versions.

screenshot

Going Responsive

This project serves as a good example of the difference between a responsive design and a fluid one. At this point, our menu is fluid (it uses percentage-based widths) but it isn’t responsive. We can see this clearly when we attempt to reduce the size of our window too much:

screenshot

As you can see, this is a wreck! Let’s jump in with some media queries to see if we can fix this problem. The best way to find out where we need media queries is simply to test it out and see where the layout breaks, then account for it.

1220px

The first problem that I see occurs around 1,200 pixels wide. Here the longer text items start to get cut off and are no longer fully readable.

screenshot

To fix this, we need only to adjust our font size. I target an area just before the problem occurs (1,220px) and set my fonts to 10px.

/* MEDIA QUERIES*/
@media only screen and (max-width : 1220px),
only screen and (max-device-width : 1220px){
	nav li a {
		font: 400 10px/1.4 'Cutive', Helvetica, Verdana, Arial, sans-serif;
	}
	
	nav small {
		font: 100 10px/1 Helvetica, Verdana, Arial, sans-serif;
	}
}

With that change, the problem no longer occurs. As we reduce the size of our window, the menu responds and reduces the font size to accommodate the size.

screenshot

930px

Once again we reduce the size of the window and find that things get hairy around the 900px mark. We’ve got lots of problems with overflow here:

screenshot

Rather than making the font-size smaller and smaller until you can’t see it anymore, this time we’ll completely reflow the menu so that it splits into two rows. Now each link can be nice and large given that this might be around the point where tablet sizes kick in.

@media only screen and (max-width : 930px),
only screen and (max-device-width : 930px){
	nav li a {
		width: 25%;
		border-bottom: 1px solid #fff;
		font: 400 11px/1.4 'Cutive', Helvetica, Verdana, Arial, sans-serif;
	}
	
	nav li:last-child a, nav li:nth-child(4) a {
		border-right: none;
	}
	
	nav li:nth-child(5) a, nav li:nth-child(6) a, nav li:nth-child(7) a, nav li:nth-child(8) a {
		border-bottom: none;
	}
}

Notice that we had to rethink how our borders work this time as well. Now we need the top row to have borders on the bottom, but not the bottom row. Once again, pseudo class selectors make this pretty easy.

screenshot

580px and 320px

The two row format works well enough until we get below 600px and then all hell breaks loose. The thing just completely falls apart.

screenshot

To address this, we’ll finish off our media queries with a two column, four row format. We’ll use this layout for 580px below and bump the font-size down a little at 320px.

@media only screen and (max-width : 580px),
only screen and (max-device-width : 580px){
	nav li a {
		width: 50%;
		font: 400 12px/1.4 'Cutive', Helvetica, Verdana, Arial, sans-serif;
		padding-top: 12px;
		padding-bottom: 12px;
	}
	
	nav li:nth-child(even) a {
		border-right: none;
	}
	
	nav li:nth-child(5) a, nav li:nth-child(6) a {
		border-bottom: 1px solid #fff;
	}
}

@media only screen and (max-width : 320px),
only screen and (max-device-width : 320px){
	nav li a {
		font: 400 11px/1.4 'Cutive', Helvetica, Verdana, Arial, sans-serif;
	}
}

Our menu now looks good even at a very small size. The downside is that it does take up a decent chunk of vertical height, but you can remove some of the padding if that bothers you.

screenshot

Selectivizr

screenshot

The astute observers among you will notice that we accounted for older versions of IE with the html5shim, only to follow that with some fancy pseudo class selectors that won’t work in IE either. To account for this, be sure to download and implement Selectivizr, a fancy JavaScript utility built specifically for bringing CSS3 selectors to IE6-8.

Conclusion

Responsive design is no walk in the park. It takes time, effort and plenty of “know how” to pull off effectively. I like to break it down into individual challenges like the navigation menu here and the image gallery in a previous article so you can learn the process without feeling overwhelmed.

You should now be well equipped to embark on your own responsive navigation menu project. Leave a comment below and show us what you come up with. What unique challenges did you face along the way?

Comments & Discussion

38 Comments

Comments & Discussion

38 Comments

  1. Thomas says:

    Nice Article, Thanks!

    But it seems very much extra work to make a whole website responsive as there are many more sections to restyle for smaller screens than just the navigation …

    I wouldn’t use small for the subline – that elements is intended for “smallprint” like copyright info. an em, strong or even span would be a better choice in your case

  2. Chris says:

    Excellent article! I’ve been using responsive design for personal and professional sites for some time now but the question of how to handle primary navigation menus has always been the toughest part of the design process for me and I was starting to get in a rut with my menu design solutions. This article gives me some new ideas for approaching the problem.

  3. ethan says:

    Very very cool, and simple, too. Thank you.

  4. Mircea says:

    I don’t see the point of the added . You can add display:block to the element and get the same effect while using less markup.

  5. Mircea says:

    I don’t see the point of the added br. You can add display:block to the small element and get the same effect while using less markup.

  6. Joshua Johnson says:

    Good idea Mircea!

  7. Tiffany says:

    Does this not work in Firefox? I resized in Firefox and the menu never changes from a two-column, four-row fixed size.

  8. josh says:

    the example on Dabblet is horridly slow.

    Does it run any better if I put it together?

  9. Badiuzzaman says:

    I did a nice navigation only @480px.

    have a look how nested li,ul element change their behavior…….

  10. Badiuzzaman says:

    Obviously it so nice..

  11. Personally, I wouldn’t take this approach because it takes up far too much screen real-estate. If the navigation is as long as this, a select list is a far more better approach.

  12. imran ali says:

    First of all nice tutorial and thanks for your time, i have a question how do you catch the sizes of the browser window screen in tutorial, are you doing it with Photoshop or is their an easier way of doing this?

  13. Edson says:

    Very well done! I notice you have set a white 1px border for the links and you done that way just for the example, isn’t it? Perhaps a better way to do that is just set a 1px margin since the nav is on a white background. Wondering why you used px for font size. Why not em or %? This trick has something to do with the height of the block level link? For the final touch of this cool example I would recommend to set a “visible hidden” for the small tags (or the break line just before them could mess up everything adding extra padding down?)
    I’ll try to do something like this for practice. Thanks for share!

  14. Alex says:

    Very nice article and food for thought! I agree with my predecessors that a tag could be replaced by display:block;
    If you are looking for a way so that the navigation takes up less screen-estate, the approach mentioned by Stephen is very good. Brad Frost describes a few more options in his recent article: http://bradfrostweb.com/blog/web/responsive-nav-patterns/

  15. Varemenos says:

    have you actually tried viewing the menu at 240×320?

  16. Ragtech says:

    I tried to see the demo with IE8… nogo! and, also not good!

  17. Lindsey says:

    Loved this tutorial. I agree, breaking it down really helps. Thank you!

  18. verpixelt says:

    hi, first of all, thx to you 4 this tutorial. I started with HMTL/CSS in Summer 2011 so my knowhow isnt that big @ the moment but the tutorial was easy to follow and i learned quite a few things. So thanks again and keep up doing such good tuts!!! thumbs up!

  19. makarand says:

    Very good explanation given, I tried it in first time only. Thanks for the menu :)

  20. Uriel says:

    Thank you very much Joshua is a very good tutorial.
    I’m a newbie with html5 and I’m not very good at speaking English (I speak Spanish), but is very easy to understand.
    Josh: just download the .js instead of linking and works very fast.
    Ragtech: works great in Internet Explorer 8, only download and links the html5shiv.js and Voila!

  21. Vi says:

    I love this navigation menu! It’s clean and beautiful. One problem I am encountering though is that the transitions don’t work after clicking on the links in Chrome. I know it’s a bug but I’m not sure if there’s already a workaround for this?

    Thanks again!

  22. Miguel says:

    Tried this on a couple different devices(iphone and android galaxy) and it doesnt seem to resize to the smaller screen. Rather, it just scales the initial view one gets on a “normal” pc width screen.

  23. That’s good, i was looking for this. Hope i i will be able to code it right

  24. Vi says:

    @Miguel I encountered this same problem recently and I found that adding this – – in the header solved the problem.

  25. Vi says:

    @Miguel guess the snippet didn’t show. let me try again, it’s this – meta name=”viewport” content=”width=device-width, initial-scale=1.0″ / – in between “less than” and “greater than” brackets.

  26. Aldo says:

    Thanks!!

    what if I had to include a drop down option?? I mean a drop down menu in the first button??? how can I do that??

    thanks

  27. Cristi says:

    Well, thank you Joshua. Done! Now I’ll just modify Zurb Foundation’s default menu.

  28. Gerry O'Neill says:

    The author includes:
    -ms-transition: background 0.5s ease;
    Yes I have IE9 and this has no effect, am I missing something here?

    Great tutorial, but theres bits that need clarifying!

  29. rushdan says:

    Good Job. But i don’t understand about box-sizing even I have read it on wwwschool. Maybe I had a limit of english language. so sad

  30. Chris says:

    Thanks. Really useful!!

  31. Garrett Massey says:

    Great tutorial! I have one question though, if I wanted each link to highlight into a different color when you hovered over it, how would I go about doing that?

  32. Shrish says:

    Create Work….!!!

  33. Sridhar says:

    Very well nice navigation i would like for as long as navigation better approach

  34. Trina says:

    Thanks for this! Do you have one with submenu or pulldown? Most of the nav bar I design have sublinks under each main category. Please advise.

  35. Cenco says:

    Great thanks a lot for making this nice menu available and being so up-to-date and progressive at the same time!

  36. Ian Baldwin says:

    This was really helpful with a project I am working on. Thanks!

  37. It’s very easy to find out any topic on net as compared to textbooks,
    as I found this paragraph at this web page.

Leave a Comment

Subscribe
Membership
About the Author