Examining Responsive Navigation Patterns
As web designers create more and more responsive sites, patterns continually emerge for how we handle global navigation. This is the first in a series of posts focused on how to develop some of those patterns. This post will cover three responsive navigation patterns; the top-nav, priority, and select menu.
One of the specific problems almost every responsive site has to deal with is what to do with the global navigation. A navigation bar or menu that fits comfortably on a wide screen can easily become cramped on a small screen. An array of solutions have emerged, thanks to experimentation by the world's web designers, to handle this issue.
Brad Frost collected many of these responsive navigation patterns and then collected some more complex patterns. This post is the start of a series exploring a number of these patterns, specifically how to develop them yourself, rather than leaning on a copy-paste approach. We'll look at three similar patterns and consider additional groups of patterns in future posts.
The Patterns
The basic problem with responsive navigation is one of space. On wide screens we have plenty of horizontal space to work with, but that isn't the case on smartphones and similarly small devices. We could convert the horizontal space to vertical space on these small devices, but that pushes the content further down the page. These patterns look to keep navigation available while limiting the vertical space used.
The 3 patterns we'll look at in this post are the:
- Top-Nav (do nothing) — keeps menu items to a minimum and uses css to adapt the navigation.
- Priority — prioritizes menu items to show and hide their display based on the available screen width.
- Select Menu — converts a navigation bar to a select menu where the available space is limited.
Each of these patterns attempts to solve the space problem in a different way.
The demo shows all three patterns, plus a variation on the select menu pattern. Below I'll walk through each, though I'll keep the code limited to the header of each page to keep things a little simpler.



Top-Nav (Do Nothing) Pattern
The top-nav pattern is probably the most common approach in use. The changes between narrow and wide screen are minimal, hence the nickname "do nothing." Usually all that's necessary is some minor tweaks to your css to get this pattern working.
Approach: The demo has a very simple header. It includes a logo and several links making up our global navigation. Our challenge is to transition between the navigation sitting below the logo and shifting it up and to the right once enough space is available.
Step 1: The HTML
The markup is fairly simple. Inside an html5 header element we have a logo and an unordered list of links for our navigation. The container div is simply a way to allow the background of the header to stretch from edge to edge, while keeping the content within centered with a max-width. It works the same as wrapping your entire code in a single container, but allows more flexibility in what is and isn't contained.
One thing you might wonder about is the use of non-breaking spaces in the menu labels. As the browser resizes, the menu items will want to jump between one and two lines. The non-breaking spaces ensure the complete label will always remain on a single line, avoiding ugly word-wrapping.
1 |
<header>
|
2 |
<div class="container"> |
3 |
<img class="logo" src="images/logo.png" width="252" height="46" /> |
4 |
|
5 |
<nav>
|
6 |
<ul id="demo-nav"> |
7 |
<li><a href="">Back to Post</a></li> |
8 |
<li class="current"><a href="">Top-Nav</a></li> |
9 |
<li><a href="">Priority</a></li> |
10 |
<li><a href="">Select Menu</a></li> |
11 |
<li><a href="">Select Menu JS</a></li> |
12 |
</ul>
|
13 |
</nav>
|
14 |
|
15 |
</div>
|
16 |
</header>
|
Step 2: The Default CSS
The default css for the header and logo is also fairly simple. The header itself gets some color styles and a bit of padding at the bottom. On small screens we'll have the navigation below the logo and we'll center both. I've given the logo itself some margin to add a little space above and below.
1 |
header { |
2 |
color:#eee; |
3 |
background: #2b2726; |
4 |
padding-bottom: 1em; |
5 |
text-align: center; |
6 |
}
|
7 |
|
8 |
.logo { |
9 |
margin: 1.25em 0; |
10 |
width: 200px; |
11 |
}
|
The default css for the navigation, again, is fairly simple. If you've ever coded a navigation bar before it should look familiar. One thing often included in a navigation bar, but missing here, is a float on the links. Since we're going to center everything by default we'll save the float till we need it.
1 |
#demo-nav { |
2 |
margin: 0; |
3 |
padding: 0; |
4 |
list-style: none; |
5 |
overflow: hidden; |
6 |
}
|
7 |
|
8 |
#demo-nav li { |
9 |
display: inline; |
10 |
}
|
11 |
|
12 |
#demo-nav a { |
13 |
color:#fff; |
14 |
padding: 0.75em; |
15 |
text-decoration: none; |
16 |
line-height: 2.5; |
17 |
}
|
18 |
|
19 |
#demo-nav a:hover { |
20 |
text-decoration: underline; |
21 |
}
|
The key to the above is the spacing between links. Not enough space and the individual links will be hard to tap. Too much space and your navigation will drop to an extra line and take up more vertical space. What I've done is seek a compromise that allows as much room between links as possible while keeping the rows of links to a maximum of two.
With the styles above the navigation should look like you see below. The screenshot was taken with my browser open to 320px.

Step 3: The Media Queries
The first couple of media queries are to adjust the space between links. We won't have enough room to move the navigation up and to the right for a bit, but on the way we can adjust the padding of the links as room allows. There's no right or wrong amount. I just played around with the browser width and made adjustments at various points.
At 42.5em (680px) there's enough room to fit all the links on a single line so I reduced the left and right padding to fit them all in the one line.
1 |
@media screen and (min-width: 30em) { |
2 |
#demo-nav a {padding: 0.75em 1.75em;} |
3 |
}
|
4 |
|
5 |
@media screen and (min-width: 42.5em) { |
6 |
#demo-nav a {padding: 0.75em 1.1em;} |
7 |
}
|



Once the screen gets to about 52.5em (840px) there's enough room to move the navigation bar up and to the right of the logo. First we'll float the logo to the left. The padding at the bottom of the header is no longer needed so we'll remove it.
We'll float the navigation bar to the right and reduce the left and right paddings of the links a little more and the navigation jumps into place. Since we're floating it right I removed the right padding on the very last link. One last change is setting the links to display as block level elements to increase the size of the clickable area and because of that change the links now need to be floated.
1 |
@media screen and (min-width: 52.5em) { |
2 |
.logo {float: left;} |
3 |
header {padding-bottom: 0;} |
4 |
|
5 |
#demo-nav {float: right;} |
6 |
#demo-nav a {padding: 1.25em 0.75em; display: block; float: left} |
7 |
#demo-nav li:last-child a {padding-right: 0;} |
8 |
}
|



These last two changes are once again solely to adjust the spacing between links and again the changes were more according to my eye than anything else.
1 |
@media screen and (min-width: 64em) { |
2 |
#demo-nav a {padding: 1.5em;} |
3 |
}
|
4 |
|
5 |
@media screen and (min-width: 75em) { |
6 |
#demo-nav a {padding: 1em 2.25em; line-height: 3em} |
7 |
}
|
Tips
This is a fairly simple pattern, which is why you see it used so frequently. Depending on your design it's possible you really don't need to change anything, beyond a few tweaks here and there.
This pattern works best when the number of menu items is limited. I used five here. Six would probably work. Four probably works better.
The main thing to watch out for is to make sure to leave enough space around links on narrow screens so each can be selected. Keep in mind on a phone you won't be making the selection with a precise mouse. You'll be using your fingers which aren't as precise.
The other thing to keep in mind is the link labels will want to break over lines at some widths. Here I used a non-breaking space to prevent that, which isn't necessarily the ideal solution.
Examples
The sites below are all using the top-nav pattern



The Priority Pattern
The top-nav patterns works fine when you only have a few links in your navigation. Sometimes you can't reduce the number of menu items to four or five though, and the pattern breaks down. It ends up requiring too much vertical space on the smallest screens.
However, while you may need more links, there are likely some that are more important than others. That's where the priority pattern comes in. The idea is to specify a priority for the links through classes on the menu items.
On the widest screens all the links show. As the browser gets smaller the lowest priority links become hidden behind a "more" link. As the browsers gets even smaller the next level of links is hidden. On the smallest screen you use a minimum of vertical space until the visitor asks for "more" links.
Approach: Once again the demo has a simple header. This time it includes more links so we'll keep the navigation below the header at all times. We have 2 separate challenges in transitioning the menu from small to wide screens.
- Show and hide some links by default
- Show and hide some links when requested
Step 1: The HTML
The html is similar to the top-nav pattern. The differences are the additional links and the "more" and "less" links we'll use to show and hide other links. Also included are the priority classes (alpha, beta, gamma) given to each list item and the show-more and show-less classes.
1 |
<header>
|
2 |
<div class="container"> |
3 |
<img class="logo" src="images/logo.png" width="252" height="46" /> |
4 |
|
5 |
<nav>
|
6 |
<ul id="demo-nav"> |
7 |
<li class="alpha"><a href="">Back to Post</a></li> |
8 |
<li class="alpha"><a href="">Top-Nav</a></li> |
9 |
<li class="current alpha"><a href="">Priority</a></li> |
10 |
<li class="alpha"><a href="">Select Menu</a></li> |
11 |
<li class="beta"><a href="">Select Menu JS</a></li> |
12 |
<li class="beta"><a href="">Beta Link</a></li> |
13 |
<li class="gamma"><a href="">Gamma Link</a></li> |
14 |
<li class="gamma"><a href="">Gamma Link</a></li> |
15 |
<li class="show-more"><a href="#more">More</a></li> |
16 |
<li class="show-less"><a href="#">Less</a></li> |
17 |
</ul>
|
18 |
</nav>
|
19 |
|
20 |
</div>
|
21 |
</header>
|

Step 2: The Default CSS
The default styling is identical to the default styling for the top-nav pattern above so I won't repeat it here. The exception is the need to show and hide links. There are 2 parts to doing this.
First we only want to show the alpha links and the "more" link on the smallest screens so we'll set the other links to display: none
.
1 |
#demo-nav li.beta, |
2 |
#demo-nav li.gamma, |
3 |
#demo-nav li.show-less |
4 |
{display: none;} |
Secondly we need to show and hide the other priority links and swap the "more" and "less" links when either is clicked. To do this we'll take advantage of the :target pseudo-selector. If you're not familiar with this selector it's similar to how a named anchor works.
The :target selector matches when the hash in a url and an id on an element are the same. In other words if you have the url domain.com#more then :target will match any element with id="more"
added.
You may have noticed in the html above that the href of the "more" link is #more. Clicking it will take us to the same page with the hash #more added. What I didn't show above was the html element on the page.
1 |
<html lang="en" id="more"> |
Clicking more will allow us to target the html tag using the :target pseudo selector and consequently anything contained within the html tag. We can show the hidden links and hide the "more" link with the following.
1 |
:target #demo-nav li.beta, |
2 |
:target #demo-nav li.gamma, |
3 |
:target #demo-nav li.show-less |
4 |
{display: inline;} |
5 |
|
6 |
:target #demo-nav li.show-more { |
7 |
display: none; |
8 |
}
|
When someone clicks the "less" link we remove the hash and these :target selectors no longer take effect.
Note: While I added the id="more"
to the html tag, any high level element in the DOM can work. It just needs to be something that contains all the elements you ultimately want to select.

Step 3: The Media Queries
As I did in the top-nav example I have some media queries set up where all that changes is the padding between links. I also switched from centering everything to floating both the logo and navigation bar to the left, though for this pattern I kept the navigation below the logo.
I won't present all that code, though you can see it on the priority pattern demo page. Instead let's focus on revealing the lower priority links which is quite simple. All we need to do is show each priority level of links as enough space to show them becomes available. We'll show the beta links first and then the gamma.
1 |
@media screen and (min-width: 48em) { |
2 |
#demo-nav li.beta {display: inline;} |
3 |
}
|
4 |
|
5 |
@media screen and (min-width: 75em) { |
6 |
#demo-nav li.gamma {display: inline;} |
7 |
|
8 |
#demo-nav li.show-more, |
9 |
:target #demo-nav li.show-less |
10 |
{display: none;} |
11 |
}
|
Once all 3 priority level of links can be displayed we no longer need to show either the "less" or "more" links so we'll turn them off completely.



Tips
Of all the patterns, the priority pattern is the one you'll likely use least, but it can be a good solution in some cases. It has a few drawbacks. For one the :target pseudo-selector doesn't work in IE8 and below. IE6 and IE7 are easy to give up, but I think we realistically need to support IE8 a little longer. You can replace the :target method above with a javascript solution to show and hide links for IE8 instead.
A bigger issue is the toggle between more and less links can be somewhat jarring. In this example I've placed these links at the end and clicking one leaves the other in a different location. They feel like they should just swap in place, but they don't.
You can compensate by placing the links first in the list or by using multiple pairs of them that always show up after the priority links being displayed and before those that are hidden by default, but neither is the most elegant solution.
Examples
Two of the following examples are demos, with the last being an example of this pattern used on a live site.



The Select Menu Pattern
The select menu pattern is another way to solve the problem of too many links for a small screen, however it does so by converting your list of links to a select box. The advantage is the select box will take up less vertical space. The disadvantage is your global navigation links are hidden by default.
Another disadvantage is you need to code both types of navigation in your html as there's no way to make a select look like a list or vice versa. This means you'll need to maintain 2 menus, which can be a pain if you have more than a few links. I'll get to another version of this pattern in a bit where javascript is used to create one of the menus.
Approach: We'll start with two html menus, one the same unordered list we used for the top-nav pattern and one a select element. We'll transition from one to the other in a media query as space allows. We'll also need to add a bit of javascript so selecting an option takes us to a new page.
Step 1: The HTML
There's nothing new in the unordered list version of the menu. What's new is the addition of the select box and corresponding options. The values of the href attribute are moved to the value attribute of the option element.
1 |
<div id="header"> |
2 |
<div class="container"> |
3 |
<img class="logo" src="images/logo.png" width="252" height="46" /> |
4 |
|
5 |
<nav>
|
6 |
<ul id="demo-nav"> |
7 |
<li><a href="">Back to Post</a></li> |
8 |
<li><a href="top-nav.html">Top-Nav</a></li> |
9 |
<li><a href="priority.html">Priority</a></li> |
10 |
<li class="current"><a href="select.html">Select Menu</a></li> |
11 |
<li><a href="select-js.html">Select Menu JS</a></li> |
12 |
</ul>
|
13 |
</nav>
|
14 |
|
15 |
<select id="select-menu"> |
16 |
<option value="" selected="selected">Select</option> |
17 |
<option value="">Back to Post</option> |
18 |
<option value="top-nav.html">Top-Nav</option> |
19 |
<option value="priority.html">Priority</option> |
20 |
<option value="select.html">Select Menu</option> |
21 |
<option value="select-js.html">Select Menu JS</option> |
22 |
</select>
|
23 |
</div>
|
24 |
</div>
|
Step 2: The Default CSS
The general default styling is the same as those I've shown above so I won't repeat it here. For the smallest screens I decided to drop the select menu below the logo and leave it centered. Giving it a width of 75% seemed to be all that was needed.
1 |
#select-menu { |
2 |
width: 75%; |
3 |
}
|

Step 3: The Media Queries
The css in the media queries is again pretty simple. Since the select menu doesn't take up a lot of horizontal space we can move it up and to the right of the logo relatively quickly.
1 |
@media screen and (min-width: 30em) { |
2 |
.logo {float: left;} |
3 |
|
4 |
#select-menu { |
5 |
float: right; |
6 |
clear: none; |
7 |
width: 40%; |
8 |
margin-top: 2.25em; |
9 |
}
|
10 |
|
11 |
#header {padding-bottom: 0; text-align: left;} |
12 |
}
|
The main change is hiding the select menu and showing the unordered list menu, which we can easily do through the display property of both. In terms of accessibility this is also advisable as screen-readers will only need to scan the navigation once. With the unordered list displayed we'll float it to the right and adjust the padding of the links.
1 |
@media screen and (min-width: 64em) { |
2 |
#select-menu {display: none;} |
3 |
|
4 |
#demo-nav { |
5 |
display: block; |
6 |
float: right; |
7 |
}
|
8 |
|
9 |
#demo-nav a {padding: 1.25em 1.5em;} |
10 |
#demo-nav li:last-child a {padding-right: 0;} |
11 |
|
12 |
}
|
Beyond the above I made one additional change to give the links a little more padding on wider screens.
Step 4: A Little Javascript
This pattern does need a small amount javascript so that the options in the select menu will take us to new pages. Here I used a small bit of jQuery (after including jQuery in the head of the document).
1 |
$(function() { |
2 |
$("div select").change(function() { |
3 |
window.location = $(this).find("option:selected").val(); |
4 |
}); |
5 |
}); |
Examples
The sites below are all using the select menu pattern.



Select Menu JS
I mentioned above that you could use javascript to create the select menu so you don't have to maintain two sets of identical links. Once again I'll use jQuery to create the select menu from the unordered list with some code borrowed from Chris Coyier.
First we create the select and append it to our nav element. The next block creates the "Select" option which we'll show by default. This isn't really needed. Instead you might let your first menu item show, or perhaps you'd add a little code so the option for whichever page you're on is the one selected by default.
The last block grabs each link from the unordered list and adds the url and text to the appropriate part of the option element.
1 |
$(function() { |
2 |
// Create the dropdown base |
3 |
$("<select id='select-menu'/>").appendTo("nav"); |
4 |
|
5 |
// Create default option "Select" |
6 |
$("<option />", { |
7 |
"selected" : "selected", |
8 |
"value" : "", |
9 |
"text" : "Select" |
10 |
}).appendTo("nav select"); |
11 |
|
12 |
// Populate dropdown with menu items |
13 |
$("nav a").each(function() { |
14 |
var el = $(this); |
15 |
$("<option />", { |
16 |
"value" : el.attr("href"), |
17 |
"text" : el.text() |
18 |
}).appendTo("nav select"); |
19 |
}); |
Finally we end with the same jQuery as above to ensure the options take the visitor to their selected page.
1 |
$("nav select").change(function() { |
2 |
window.location = $(this).find("option:selected").val(); |
3 |
}); |
4 |
}); |
Summary
These are three of the common patterns used to handle responsive navigation.
The top-nav pattern works best when you only have a few links and doesn't need much other than whatever stylistic changes you decide to make.
The priority pattern can be used when you have more than a few links. It hides different levels of prioritized links based on available space and toggles the display of the links through the :target
pseudo selector.
The select menu pattern converts unordered list menus into select menus so as not to take up any extra vertical space.
There are more patterns beyond these and we'll look at them in future posts in this series. Thanks for reading!