Creating a CSS3 Responsive Menu

Creating a CSS3 Responsive Menu

Today, I’m going to create a responsive menu using CSS3. 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.

I used Respond.js and IE HTML5 enabling script so that HTML5 and media queries will work on Firefox 2 and IE. I also used html5doctor.com’s Reset Stylesheet for the demo.

Note: The demo works on Chrome, Firefox, Safari and IE8+.

Check out the demo below to see how it works, and feel free to download the example for future use and experiment.

Creating a CSS3 Responsive Menu

[tut demo=”http://www.onextrapixel.com/examples/css3-responsive-menu/” download=”http://www.onextrapixel.com/examples/css3-responsive-menu/css3-responsive-menu.zip”]

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

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 id="banner" role="banner">
    <div id="banner-inner-wrapper">
        <div id="banner-inner">
            <hgroup id="title">
                <img id="logo" src="image/logo.png" title="Responsive Bar" />
            </hgroup>
            
            <nav id="menu-nav">
                <!-- button to show and hide the menu -->
                <div id="menu-button">
                    <div id="menu-button-inner"></div>
                </div>
            </nav>
            
        </div>
    </div>
    
    <!-- menu itself -->
    <nav id="menu-drink">
        <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 & 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 {
    background-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:

320 Menu

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 (!open) {
                // Hide the menu if it's not supposed to be displayed
                $("#menu-drink").hide();
            }
            // Display the button
            $("#menu-button").show();
        }
        else 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.

[tut demo=”http://www.onextrapixel.com/examples/css3-responsive-menu/” download=”http://www.onextrapixel.com/examples/css3-responsive-menu/css3-responsive-menu.zip”]

Conclusion

What do you think of this tutorial. Do you have any other tips on creating a responsive menu with CSS3? Share with us in the comment box below.

Shingo is a web developer based in New Zealand with 8+ years of programming experience. He deals with a wide range of platforms on a day-to-day basis, but his true passion is creating interactive web components using CSS and JavaScript.

Comments

    • TallBotPeach,
    • August 27, 2012
    / Reply

    Just one question: can you give exposition on why you used N/16 for all of your padding/margins?

    1. / Reply

      I used N/16 to work out the padding/margin in ’em’ based on the current font size. I cover a bit about it on “Set the font-size to set up a flexible system” of this tutorial http://www.shingokko.com/blog-entry/responsively-design-a-blog.html

    • Alex,
    • August 28, 2012
    / Reply

    Why would you not include the media queries CSS in a responsive article??

    Pretty inappropriate.

    1. / Reply

      The article does explain briefly what I did for each media query so refer to the actual CSS file. Let me know if you have specific questions about how I styled the menu that I didn’t include in the article.

  1. / Reply

    What’s the support for IE on this?

  2. / Reply

    oh sorry just noticed toward the bottom of the article it mentions it is supported by ie8 and above

    • Kazuhito Kidachi,
    • August 31, 2012
    / Reply

    If JavaScript is disabled but CSS is enabled, this technique doesn’t work well.

  3. / Reply

    In Google Chrome 23.0.1251.2 dev-m demo not working

    1. / Reply

      Sorry all working fine. It’s my inattention

  4. / Reply

    Good discussion i have seen :-). But i Really appreciate this article, as it gives a basic explanation about responsive designing.

  5. / Reply

    Pretty cool tutorial, checked the demo and everything is perfect. Will try to implement this on my blog…

  6. / Reply

    I need a simple help. where to add the Jquery code, in my css file or any other file?

    1. / Reply

      You can add a script tag in the head tag of the markup, or create a js file with the code in it and add a script tag referencing the file. Download the demo and look at the contents of ‘index.html’, you should be able to see how the code is added.

      • Tasleem Aarif,
      • March 22, 2013
      / Reply

      Add Jquery code inside the header tag of your page. not in css.

    • eric,
    • October 7, 2012
    / Reply

    This menu is good but i find it difficult to customize especially for a beginner like me.

  7. / Reply

    Any suggestions to work with this and a menu with sub-pages? like a drop-down menu?

    • Ali,
    • December 11, 2012
    / Reply

    Very nice a menu example. Thanks for tutorial.

  8. / Reply

    I specially liked the mouseout effect.. Is that the javascript magic?

  9. / Reply

    Thank you very very much !! It’s a really very useful and well done tuto ! Thanks !

  10. / Reply

    Boom!! exactly what i was searching for.. awesome tutorial .. Thanks

    • leighmasson,
    • November 26, 2013
    / Reply

    Simpler than Twitter’s bloated bootstrap! Just what I was after. Neat animations and touches too.
    Good to see great comments in your code, and easy to understand syntax.

    My one question;
    I want to keep the bar the same height regardless of screen width. ie- when the browser width is greater than 1024px the height or there navigation bar is rather tall- I want to restrict it to 36px… regardless of screen width to keep it consistent.
    I’ve tried adjusting the banner wrapper height, but then the links sit below the bar etc.

    I still want to take advantage of the compact menu that collapses when the browser is resized (or when using a mobile).

    I can include screenshots also if you would like to see how I am using it.

    • leighmasson,
    • November 27, 2013
    / Reply

    How can I make the height of the navigation bar fixed? I’d like to make it 36px high…
    I find the bar on the larger browser sizes too big.

    I tried restricting the wrapper- but then I find the other elements such as the navigation links go out of proportion/ fall off the bar.
    Of course, I still want to take advantage of the navigation bar which turns into a menu on smaller screens.

    Otherwise, great tutorial. Much better than Twitter’s bootstrap solution which is bloated and difficult to pull apart. Your syntax and comments in the code are helpful and make this digestible!

Leave a Reply

Your email address will not be published. Required fields are marked *

Deals

Elegant Themes Coupon Code: 20% discount

While most other WordPress theme sites charge per theme, Elegant Themes is an amazing deal as you pay just once for access to 87 premium WordPress themes and a…

WrapPixel Coupon – 25% Discount

If you’re looking for an HTML or PSD template for your next website, checkout the selection of templates at WrapPixel made for web developers, designers, and agencies. You can…