SEARCH
  Tutorials HTML and CSS Tutorials Creating a CSS3 Responsive Menu

Creating a CSS3 Responsive Menu

This tutorial aims to provide step by step instructions to enable you to create a responsive navigation menu that adapts to varying screen sizes, with the help of CSS media queries.

Creating a CSS3 Responsive Menu

Creating a CSS3 Responsive Menu

Design Parameters: work your way up to larger screens

I adopted the Mobile First approach to designing the menu. In essence, this approach adopts a strategy of designing for mobile devices first, then working your way up to larger ones, such as desktop monitors. The base design is developed for the popular dimensions of mobile devices - 320 x 480. I then utilised media queries, primarily for scaling up to larger screen sizes, but also as an effective tool for enhancing the design.

The screen sizes for which the menu is designed are:

  • 320 x 480
  • 480 x 320
  • 768 x 1024
  • 1024 x 768

The Markup

Let's begin by looking at the markup.

Inside the header I added two nav tags, one for a button which opens the menu, whilst the other contains the menu items. Each menu item contains a with span to represent the icon.

With the objective of hiding the button #menu-button when the screen is wide enough to have the menu constantly visible next to the logo, I placed #menu-drink after #banner-inner-wrapper inside header. This will enable you to situate the menu beside or beneath the logo.

<header>
<div>
<div>
<hgroup>
<img src="image/logo.png" />
</hgroup>
<nav>
<!-- button to show and hide the menu -->
<div>
<div></div>
</div>
</nav>
</div>
</div>
<!-- menu itself -->
<nav>
<ul>
<li>
<a class="beer" href="#"><span class="icon"></span>Beer</a>
</li>
<li>
<a class="wine" href="#"><span class="icon"></span>Wines</a>
</li>
<li>
<a class="soft-drink" href="#"><span class="icon"></span>Soft Drinks</a>
</li>
<li>
<a class="coffee-tea" href="#"><span class="icon"></span>Coffee &amp; Tea</a>
</li>
</ul>
</nav>
</header>

CSS Styling

We'll now look at styling this markup with CSS.

I used a CSS table to set the layout of the contents of the header - display:table for #banner-inner-wrapper, display:table-row for #banner-inner and display:table-cell for #title and menu-nav.

Why use a CSS table? Because it's robust against layout changes and it requires less work than floats and display:inline-block if you want to maintain columns side by side.

I also set the logo to scale down to the available space of its container by applying max-width:100%. This prevents the image from staying larger than the width given to its container.

One strategy worth noting here is the use of em instead of px. A useful property of this unit is that it scales nicely to the current font size of the element. To work it out, divide the pixel amount by the current font size (in this case 16px).

#banner-inner-wrapper {
display: table;
width: 96%;
margin: 0.375em auto; /* 6/16 = 0.375em; */
}
#banner-inner {
display: table-row;
}
#title {
display: table-cell;
}
#logo {
max-width: 100%;
vertical-align: middle;
}
#menu-nav {
display: table-cell;
vertical-align: bottom;
text-align: right;
}

I styled the button that opens up the menu with plenty of CSS3. Specifically I used border-radius, box-shadow and background-image: linear-gradient(...). I also used the transition property to smooth out the transition between various states of the button.

Note that, in the CSS, I excluded browser/vendor specific properties such as -moz-transition and -webkit-box-shadow, for simplicity. In the actual CSS file these properties are included.

#menu-button {
vertical-align: bottom;
float: right;
padding: .375em; /* 6/16 = .375em */
margin: 0 .375em 0 2em; /* 6/16 = .375em, 32/16 = 2em */
opacity: .7;
cursor: pointer;
transition: all .2s linear;
border-radius: 2px;
box-shadow: 0 1px 1px rgba(0, 0, 0, .2);
background-color: #4D8EBC;
background-image: linear-gradient(top,rgba(100, 152, 190, .5),rgba(30, 82, 120, .5));
background-position: left bottom;
background-repeat: repeat-x;
}

I altered the style of the button for :active to allow it to give the impression of being selected. Additionally, I added a negative bottom margin to it so that it would sink down, to make it obvious it's been selected.

#menu-button.selected,
#menu-button:active {
opacity: 1;
box-shadow: 0 1px 1px rgba(120, 120, 120, .2);
background-color: #2E6288;
background-image: linear-gradient(top,rgba(25, 68, 99, .5),rgba(30, 82, 120, .5));
margin-bottom: -.375em; /* 6/16 = .375em */
}

I've also added a final touch - giving it an image that represents the purpose and the behaviour of the button.

#menu-button-inner {
background: transparent url(../image/menu-bg.png) no-repeat 0 0;
width: 78px;
height: 41px;
}

And here's the outcome of the CSS above:

Buttons

Now let's look up the CSS for the menu itself.

To make sure the menu does not take up the whole screen when it pops up, I considered the following three options:

  1. Option 1: Display all items vertically, each in a separate row
  2. Option 2: Display two items in each row
  3. Option 3: Display all items horizontally, all in one row

Option 1 would be the best choice if the only constraint is the width of the screen, because you don't need to worry about the items being compressed. Unfortunately, however, the height is also very limited, so I elected Option 2.

For the container of the menu #menu-drink, I used box-shadow to make it look like it's slightly floating above the content.

#menu-drink {
clear: both;
position: absolute;
width: 100%;
background-color: #2e6288;
box-shadow: 0 2px 2px rgba(25, 68, 99, .4);
display: none; /* Not shown initially */
}

To implement Option 2, I set the width of li to 50%.

#menu-drink ul {
overflow: hidden; /* clears the float */
}
#menu-drink li {
float: left;
width: 50%; /* takes up 50% of the available width */
}

The majority of the rest of the CSS for the menu is just for customising the menu items. In the CSS below, I've highlighted some important properties that are easy to overlook:

#menu-drink a {
color: #c2daeb;
white-space: nowrap;
text-decoration: none;
display: block;
transition: color 0.3s linear, background-color 0.3s linear;
box-shadow: inset 0 0 2px #0A3E64;
padding: .375em; /* 6/16 = .375em */
/* These vertically center the contents of the element */
line-height: 2.875em; /* 46/16 = 3.375em */
height: 2.875em; /* 46/16 = 3.375em */
}
#menu-drink a:hover,
#menu-drink a:active {
color: #fff;
background-color: #23577D;
}
#menu-drink .icon {
background: transparent url(../image/drink-flat.png) no-repeat 0 0;
/* This makes the icon to sit next to the text */
display: inline-block;
vertical-align: bottom;
opacity: .6;
width: 2em; /* 32/16 = 2em */
height: 2.875em; /* 46/16 = 2.875em */
margin-right: .5em; /* 8/16 = 0.5em */
transition: opacity 0.3s linear;
}
#menu-drink a:hover .icon {
opacity: 1;
}
#menu-drink .wine .icon {
background-position: 0 0;
}
#menu-drink .beer .icon {
background-position: -2em 0; /* 32/16 = 2em */
}
#menu-drink .coffee-tea .icon {
320 Menubackground-position: -4em 0; /* 64/16 = 4em */
}
#menu-drink .soft-drink .icon {
background-position: -6em 0; /* 96/16 = 6em */
}

The above mentioned CSS produces the following design, with a screen width of 320px:

 

This is it for the initial design.

The Media Queries

Noted below are the media queries I used. To keep it short and simple, I've excluded the actual CSS for styling the menu up for different screen sizes. Instead, I've inserted a comment to explain what I did for each media query:

@media screen and (min-width: 480px) {
/*
* Made all the items display horizontally as the screen is wide
* enough to accommodate it
*/
}
@media screen and (min-width: 560px) {
/*
* Made small adjustments to the margin and padding around
* the menu items
*/
}
@media screen and (min-width: 768px) {
/*
* Made the items display next to the logo. At this width the screen is
* large enough so that there is no need to hide the menu
*/
}
@media screen and (min-width: 1024px) {
/*
* At this width, everything appears little cramped so I made the
* padding around the whole thing larger to give the illusion of space.
* I also used larger and cooler icons.
*/
}

You might have noticed the use of min-width: ...px. This can be interpreted as "This media query kicks in when the minimum width is ...px".

jQuery/JavaScript

Phew, we're all done with the CSS! Now we'll look at the jQuery code for the menu. I used jQuery to show or hide the menu when the button is selected, and also when window is resized.

jQuery(function($) {
// This will hold the state of the pop-up menu
var open = false;
function resizeMenu() {
// If window is less than 480px wide
if ($(this).width() = 480) {
// If window is wider than 480px
if (!open) {
// Show the menu if it's not displayed yet
$("#menu-drink").show();
}
// Hide the button if the screen is wide enough for the menu to always show
$("#menu-button").hide();
}
}
function setupMenuButton() {
$("#menu-button").click(function(e) {
e.preventDefault();
// If already shown...
if (open) {
// Hide the menu
$("#menu-drink").fadeOut();
$("#menu-button").toggleClass("selected");
}
else {
// If not shown, show the menu
$("#menu-drink").fadeIn();
$("#menu-button").toggleClass("selected");
}
open = !open;
});
}
// Add a handler function for the resize event of window
$(window).resize(resizeMenu);
// Initialize the menu and the button
resizeMenu();
setupMenuButton();
});

Success! We now have a responsive navigation menu, neatly styled up with CSS3. Check out the demo below, and feel free to download this example for future use.

ABOUT THE AUTHOR

Onextrapixel OXP

Onextrapixel is a leading online magazine and resource site for designers and web developers. The Singapore based portal aims to collect, explore, as well as share useful tips, news, tutorials, tools and resources; on design, development and other inspiration. We hope that everyone will find something here that is useful and interesting.

subscribe to newsletter