Create a hardware accelerated mobile navigation

In this tutorial, I'll show you my favoured method for creating a responsive, mobile navigation, (like the one on facebook mobile). This works well on iOS devices and most Android devices (I've not tested on anything below Gingerbread), but I'm yet to have tried it on Windows Phone.

DemoSource Files

1. Basic HTML Structure

To begin, we will create a basic HTML structure for our site (If you're too lazy to do the strenuous task of copy and pasting this, theres a link to a download with all the source files above).

<!DOCTYPE html>

<html>
<head>
    <title>My Responsive Nav Site</title>
    <meta name="viewport" content="initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale=1.0">
    <link rel="stylesheet" href="css/main.css" />
    <script src="js/vendor/modernizr-2.6.2.min.js"></script>
    <!--[if lt IE 9]>
        <script src="js/vendor/html5shiv.js"></script>
    <![endif]-->
</head>
<body>

    <script src="js/vendor/jquery-1.9.1.min.js"></script>
    <script src="js/main.js"></script>
</body>
</html>

We'll also need to some css:

html{
     height:100%;
}
body{
     margin: 0;
     padding: 0;
     font-family: Helvetica, Arial, sans-serif;
     height: 100%;
}

h1, h2, h3, h4, h5, h6{
     margin: 0;
}

2. Adding the wrapper

To make sure when we slide our content, we don't create horizontal scroll bars, we want to wrap our site in a wrapper.

<div id="wrapper">

</div>

In your css file, give the wrapper these styles:

#wrapper{
     position: relative;
     width: 100%;
     height:100%;
     overflow-x: hidden;
}

3. Adding the header

Next we'll add in the header, and the button for toggling the navigation.

<header class="slide">
     <a href="#" id="menuToggle">☰</a>
     <h1>My Responsive Nav Site</h1>
</header>

The class slide is used later on and I'll explain its purpose then, so don't worry about it now.

header{
     position: fixed;
     top: 0;
     width: 100%;
     height: 100px;
     background: #333;
     color: #ddd;
     z-index: 2;
}

header h1{
     padding: 30px;
}

#menuToggle{
     position: absolute;
     top: 10px;
     left: 10px;
     text-decoration: none;
     color: #fff;
     font-size: 24px;
     display: none;
}

That burger icon (the three bars) isn't the prettiest thing in the world, so you may want to change this out with a font awesome icon instead.

4. Navigation

Next we'll add the navigation, normally this would sit within the header, but we will be placing it below the header, so we can re-use it in the mobile version of the site.

<nav>
     <li><a href="#">Link 1</a></li>
     <li><a href="#">Link 2</a></li>
     <li><a href="#">Link 1</a></li>
</nav>
nav {
    position: fixed;
    top: 30px;
    right: 30px;
    z-index: 3;
}

    nav > ul > li {
        float: left;
        margin-left: 20px;
        list-style: none;
    }

    nav a {
        color: #aaa;
    }

        nav a:hover {
            color: #fff;
        }

5. Content

We will add some basic content for now, just as a placeholder. Remember to add the class slide to the content div so we can target it later.

<div id="content" class="slide">
     <p>
          Lorem ipsum dolor sit amet, consectetur adipiscing elit. Etiam consectetur quam vel congue semper. 
          Aliquam vitae interdum turpis, non facilisis sem. Aenean suscipit adipiscing felis, eu sagittis
          usto scelerisque sit amet. Nulla hendrerit, urna eget tristique semper, est ipsum adipiscing ligula,
          sed tempus risus turpis sit amet sapien. Sed interdum consequat est, vel lacinia ante pulvinar vel.
          Pellentesque sodales odio nulla, ornare faucibus massa molestie eu. Pellentesque habitant morbi
          tristique senectus et netus et malesuada fames ac turpis egestas. Nulla vehicula lobortis tristique.
          Vestibulum ullamcorper pretium convallis. Fusce in odio ac turpis mattis euismod. Donec sit amet odio
          non nisl semper varius. Proin in hendrerit felis. Morbi vulputate nunc id tellus lobortis consectetur
          non vel diam.
     </p>
     <p>
          Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Phasellus
          massa leo, condimentum sed risus sit amet, lacinia laoreet mauris. Vivamus sit amet scelerisque nisl, sit
          amet volutpat mi. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae;
          Morbi ac blandit libero. Aenean auctor et nisl in dignissim. Suspendisse vehicula odio ut sem elementum, a 
          dapibus ipsum blandit. Aenean in purus dui. Mauris at facilisis nunc. Quisque semper tempor quam ut congue.
          Duis non turpis ac purus rutrum ultricies. Suspendisse ac nisl fringilla tellus mattis volutpat. Nunc in
          augue at metus mollis ullamcorper ut at elit.
     </p>
</div>
#content {
    padding: 120px 0 20px;
    width:100%;
    min-height:100%;
    z-index: 1;
    position:relative;
    background:#fff;
}

    #content p {
        margin-left:20px;
        margin-right:20px;
    }

6. Transition Styles

Next we want to add some css for our transitions. Because we are using modernizr for feature detection, we can apply styles only to browsers that support them.

.csstransforms3d .slide {
    -webkit-transform: translate3d(0,0,0);
    -moz-transform: translate3d(0,0,0);
    -o-transform: translate3d(0,0,0);
    transform: translate3d(0,0,0);
}


a, .slide {
    -webkit-transition: all .3s ease;
    -moz-transition: all .3s ease;
    -o-transition: all .3s ease;
    -ms-transition: all .3s ease;
    transition: all .3s ease;
}

7. Media Queries

Media queries are what will change the layout of the site, depending on how wide the window is. I've set my layout to change at resolutions below 768px as this is how wide the iPad screen is in portrait orientation.

@media only screen and (max-width: 768px) {

}

All the following css will sit within that @media block. First we want to add some css to change the header's appearance:

header {
        height: 44px;
        z-index:3;
    }

        header h1 {
            padding: 13px 0;
            text-align:center;
            font-size:16px;
        }

    #menuToggle {
        display: block;
    }

I've set the header height to 44px so it will match the iPhone / iPads navigation bar. We also set the menu toggle button to display:block to tell the browser to render it to the page.

We want to tweak the navigation slightly to make it sit behind everything else on the page so that when we slide everything over, it will reveal the navigation. I've also styled the list elements a little just to make them look a bit more tangible.

 nav {
        top: 0;
        right: auto;
        left:0;
        width:200px;
        min-height:100%;
        background:#555;
        z-index:1;
    }
        nav > ul {
            margin-top:54px;
            padding-left:0;
        }

        nav > ul > li {
            float: none;
            margin-left:0;
            padding:5px 10px;
            border-bottom:1px solid #666;
            border-top:1px solid #444;
        }
            nav > ul > li:first-of-type {
                box-shadow:0 -1px 0 #666;
            }
            nav > ul > li:last-of-type {
                box-shadow:0 1px 0 #444;
            }

We also need to tweak the content div's styles a little too, as we've made the header shorter.

#content {
        padding: 64px 0 20px;
        z-index:2;
  }

Next we'll add the styles that will actually move the page to reveal the content. For browsers without css 3d transforms support, we'll shunt the content over by modifying it's position left value when we append the .open class to it.

.slide {
        left:0;
}
        .slide.open {
            left:200px;
        }

This next chunk of code will cancel out the left value, and use css 3d transforms instead. We use css 3d transforms as opposed to their 2d transforms to make use of hardware acceleration, giving us a much smoother transition, especially on mobile devices.

.csstransforms3d .slide.open {
        left:0;
        -webkit-transform: translate3d(200px,0,0);
        -moz-transform: translate3d(200px,0,0);
        -o-transform: translate3d(200px,0,0);
        transform: translate3d(200px,0,0);
}

8. Adding the jQuery to make the magic happen

Finally, we'll add the jQuery code which will append and remove the .open class to the appropriate elements.

$(document).ready(function () {

    $('#menuToggle').click(function () {
        if ($('#content').hasClass('open')) {
            $('.slide').removeClass('open');
        } else {
            $('.slide').addClass('open');
        }
    });

});

PROFIT!!!! 

You should now have a fully working responsive mobile navigation! Go try it out and resize your browser window to be quite narrow to see it in action. Pretty nifty yes?

If you plan on using this with some fancy AJAX loading mechanism, you may want to add a few more lines of jQuery within the $(document).ready to close the menu after a user clicks on a menu item.

$('nav a').click(function () {
        $('.slide').removeClass('open');
});

Written by: Ben Meyrick