Building a Responsive, Mobile-First Navigation Menu

This tutorial will demonstrate how to develop a rather complex responsive navigation menu using the “Mobile-First Approach“. The aim is to present mobile users with a pseudo-native, touch-conducive and interactive interface that enables them to navigate the website with ease. Tablet users will be presented with an appropriately-sized navigation whilst desktop users will be presented with a glorious drop-down navigation menu.

The whole point of the practice of web design is to present appropriate user interfaces that feel native to the users’ environment. Due to the rising number of users from mobile and tablet devices, the “Responsive Web Design” approach has become a necessity in modern day web design. There is a new commandment in web design practice: Thou shall not discriminate against devices.

I have written a hands-on tutorial using the Progressive Enhancement technique regarding the design and development of a “Bulletproof Navigation Menu” that works across all major browsers. But nowadays more and more people are browsing the internet with mobile devices and as a result, the  existing techniques of web development – as demonstrated in my tutorial – have become archaic and produces very unpleasant experiences for mobile users.

Demonstration

Responsive Navigation Menu

Responsive Navigation Menu – Click to Open Demonstration

The solution presented here is, by no means, ideal for developing complex navigation menus, is not without limitations and should not be copied wholesale into a production environment. This is a proof-of-concept that attempts to achieve that following:

  • Mobile-first approach for development. Start with the smallest resolution and build upwards.
  • Provide a (somewhat) native User Experience for users of mobile devices.
  • Provide a complete desktop experience when browsed on large devices.

A slight warning about the demo: If you are going to stretch the corner of your browser to test how it “responds”, you may be disappointed. It is recommended that you reload the page after you have resized your viewport.

If you are keen on trying out the demonstration in your mobile device, use this shortlink:

http://bit.ly/respnav

The code is “available at Github” for your forking pleasure. You can also “download the source code” and play around.

Existing Responsive Navigation Patterns

The navigation happens to be the most important aspect of any website and it is important to provide appropriate navigability for users on any website regardless of the device they are browsing from. The problem with existing web design practice is that the content is not optimised and difficult to navigate on mobile devices.

Expert practitioners have extensively written about Responsive Web Design; patterns, best practices and what not. Some notable insights into responsive navigation design patterns are:

In the aforelinked article, I found this little sentence very intriguing:

Navigation patterns for RWD is exciting territory that we as an industry are all still exploring.
– Micheal Mesker.

The most popular solution to navigation design is, by far, the “select menu” approach, where the navigation is displayed as a select menu or dropdown menu on smaller viewports. There is a plethora of javascript libraries available for converting navigation menus to drop-downs on small screens. Some of the tools used by developers for converting their existing design to responsive are as follows:

Perhaps the reason for the popularity of this approach is that most developers are converting their existing designs to adapt to the mobile viewports. This is quite the opposite of what we are trying to achieve with the mobile-first approach.

There are some notable hands-on tutorials that demonstrate the mobile-first approach for developing responsive navigation menus:

The existing solutions are commendable work by their respective authors but they also come with some limitations.

This tutorial will follow “the toggle” pattern (as classified by Brad Frost) for building a relatively complex website navigation. The development process will be entirely mobile-first and will attempt to deliver a very native user experience to all users regardless of the device resolution.

Prerequisites

If you are downloading the source from Github, you can skip this section entirely. Please make sure that your local web server is fired up and the files are placed in your htdocs.

We are going to use fine blend of libraries and tools for development of this navigation menu. Before we get started with the development, please complete the following steps:

  1. Download the latest copy of Normalise.css.
  2. Download the latest jQuery, the latest Modernizr and Selectivizr.
  3. Download the HoverIntent library.
  4. Grab the latest Overthrow.js from Filament Group.
  5. Get an good understanding of Viewport and Device Width, if you do not already.
  6. Get your code editor fired up.

Now setup a basic file and folder structure as per the following:

The File Structure for the Demonstration

The File Structure for the Demonstration

Place the javascript libraries (jQuery, Modernizr and Selectivizr) into the js folder. Also, place normalise.css in the css folder. Now, we are set to go.

Target Segments of the Audience

The target audience will vary from project to project, depending on the business objectives of the website and the client funding it. But for the purpose of this demonstration, we have selected four broad target audiences.

Since we are building from small devices upwards towards larger screen sizes, here is the order of the segments of the audience we are going to cater for:

  1. Smartphones with a minimum device width of 320 pixels and a maximum device width of 480 pixels. This covers pretty much all smartphones out there.
  2. Small tablet and mobile devices with a resolution between 481 and 767 pixels. This includes the 4+ inch phones and the small 7-inch tablets.
  3. iPad specific stylesheet1, with a minimum device width of 768 and maximum of 1024, which defines rules that apply to both portrait and landscape orientations.
  4. Desktop devices and anything larger.

There is always the scope of further segmenting the Target Audiences. It is possible to design different layouts for portrait and landscape orientations and also for internet-enabled televisions. Some websites cater up to 6 segments using Media Queries. There is no rule of thumb or general guideline as to how many segments you should style for. The matter is entirely variable based on business requirements.

The Markup

Now that we know our target segments and have built the basic file structure, let us start with the markup.

The <head>

The code above borrows heavily from the “320 and Up Framework” and some bits and pieces from “Twitter Bootstrap” as well as the “HTML5 Boilerplate Mobile“. Unfortunately, all frameworks/boilerplates come with some useless cruft that is no good for this demonstration. So, instead of copying the boilerplates wholesale, we are only taking the useful bits and pieces.

<!doctype html>
<head>
 <meta charset="utf-8">

 <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">

 <title>Responsive Navigation Menu</title>
 <meta name="description" content="A hands-on tutorial on how to build an advanced Responsive Navigation Menu.">
 <meta name="author" content="Saddam Azad - UI Designer and Front-end Web Developer. London, UK.">

 <!-- http://t.co/dKP3o1e -->
 <meta name="HandheldFriendly" content="True">
 <meta name="MobileOptimized" content="320">
 <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

 <link rel="shortcut icon" href="/favicon.ico">

 <!-- For all browsers -->
 <link href='http://fonts.googleapis.com/css?family=Euphoria+Script|Lato' rel='stylesheet' type='text/css'>

 <link rel="stylesheet" href="css/normalise.css" media="screen">
 <link rel="stylesheet" href="css/atmosphere.css" media="screen">

 <!-- Media Queries -->
 <link rel="stylesheet" href="css/mobile-nav.css" media="screen and (min-width: 320px) and (max-width: 1024px)">

 <link rel="stylesheet" href="css/smartphone.css" media="screen and (min-width:320px) and (max-width:480px)">
 <link rel="stylesheet" href="css/tablet.css" media="screen and (min-width: 481px) and (max-width: 767px)">
 <link rel="stylesheet" href="css/ipad.css" media="screen and (min-width: 768px) and (max-width: 1024px)">

 <link rel="stylesheet" href="css/desktop.css" media="screen and (min-width: 1025px)">

 <!--[if lt IE 9]>
 <link rel="stylesheet" href="css/desktop.css" media="screen">
 <![endif]-->

 <!--[if (lt IE 9) & (!IEMobile)]>
 <script src="js/selectivizr-1.0.3.min.js"></script>
 <![endif]-->
 <script src="js/modernizr-2.5.3.min.js"></script>

 <meta http-equiv="cleartype" content="on">
</head>

Some of the notable pieces from this code are:

  • The meta tags with attributes such as HandheldFriendly, MobileOptimised and “Viewport“.
  • For the purpose of this tutorial, we are going to add a link to Google Webfonts to retrieve the fonts  ”Euphoria Script“ and “Lato“. This step is entirely optional.
  • And then we are going to use a modified bastardised version of Andy Clarke’s “Hardboiled CSS3 Media Queries” for the purpose of linking our stylesheets.

The reason for separating the stylesheets is because adding so many Media Queries within one stylesheet is perhaps not the best idea, in my opinion. This is actually quite a controversial issue and purely a matter of preference and/or situational requirement. I personally prefer the external stylesheets and I believe it serves the purpose of this tutorial better. Zoe Gillenwater has written comprehensive pros and cons for “external vs. embedded media queries” that is a must-read.

But why so many stylesheets? Here’s why:

  1. The first stylesheet is a query to Google Web Fonts for “Euphoria Script“ and “Lato“ fonts.
  2. The normalise.css is the alternative to reset.css that is much better suited for modern web design.
  3. The atmosphere.css is the colour, texture and typography separated from the layout and media-specific code.
  4. The first of the Media Queries, mobile-nav.css, defines a broad resolution window (between 320 pixels and 1024 pixels). This is the common code that would be applicable to a large range of devices – from phones to tablets. Hence, instead of replicating the code, we are creating a separate stylesheet.
  5. The smartphone.css targets devices between a width of 320 and 480 pixels, as defined in our list of Target Audiences.
  6. The following is tablet.css which accounts for #2 on the Target Audience list: tablets (and large phones) between the resolutions 481 and 767 pixels.
  7. Next comes the ipad.css. With this stylesheet, we will cover both the portrait and landscape orientations.
  8. The next one is the desktop.css for screens larger than 1025 pixels.
  9. Since Internet Explorer 8 and below do not support Media Queries, we are going to tell older IE versions to accept desktop.css as the default stylesheet through conditional comments.

Once the Media Queries are set up, there are some other interesting bits in the <head>:

  • We will have to embed Selectivizr for Internet Explorer 8 and below.
  • Embed Modernizr for all browsers.
  • Lastly, we have added a meta tag to activate cleartype rendering in Mobile IE for smooth font rendering.

The <body>

Now that we’re done with the head, let us build the essential bits of the body. Within the header element, we have set up the branding and tagline as headings.

<body>
<header role="banner">
  <h1 id="branding"><a href="#">Responsive Navigation</a></h1>
  <h2 id="tagline">A beautifully crafted responsive navigation menu</h2>

  <nav>

    <a data-toggle="collapse">
      <span></span>
      <span></span>
      <span></span>
    </a>

    <ul id="menu">
    ...
    </ul>

  </nav>
</header>

After the branding and tagline comes the most crucial nav element and there are two components within:

  1. An anchor with class btn — and within it lies three span elements. This bit of the code is borrowed from the “Navbar Component” of the Bootstrap framework.
  2. An unordered list called ‘menu’. The list items would be enclosed within the unordered list but they are not demonstrated here for the sake of clarity.1 Get the whole markup from Github.
  3. Note that the menu contains a classname of ‘overthrow’. This is a requirement of Overthrow.js as it enables greater support on mobile devices (using pollyfills where necessary and graceful degradation when not supported).

Apart from the header element, there are space fillers such as a section element with some content and a footer element with credits. These are non-essential for the tutorial.

Before we skip to the stylesheets, let us have a look at the bottom part of the html document.

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js"></script>
<script>window.jQuery || document.write('<script src="js/jquery-1.7.2.min.js"><\/script>')</script>

<script src="js/plugins.js"></script>
<script src="js/helper.js"></script>
<script src="js/script.js"></script>

</body>
</html>

As you can see, there are quite a few javascript files being linked to:

  • Firstly, it is a call to the Google CDN for the jQuery library. In the event that jQuert fails to load from the CDN, it will be found within the ‘js’ folder of our structure.
  • The plugins.js file is borrowed from the HTML5 Boilerplate and can be found in the “Github repo“.
    • It is recommended that you append all additional jQuery libraries with this file.  It would save us an additional HTTP request for each library and keep all the libraries in one place.
    • Append the “HoverIntent” library.
    • Append “Overthrow.js” as well.
  • The helper.js is borrowed from the Mobile Boilerplate.
  • The script.js will be a blank document for now but we are going to need it later.

The Stylesheets: Atmosphere

Now that our markup structure is complete, let us move on to the stylesheets. Apart from the link to Google Web Fonts, the next stylesheet embedded into our document is normalise.css.

The following stylesheet is the atmosphere.css. There are bits of the CSS styling that apply to elements regardless of the resolution. An example would the background-image of the document. The colour, texture and typography remain constant across all devices. This is aptly-named as the “atmosphere” of the design by Andy Clarke, the author of 320-and-Up.

/* The clearfix method */
.clearfix {
  *zoom: 1;
}
.clearfix:before,
.clearfix:after {
  display: table;
  content: "";
}
.clearfix:after {
  clear: both;
}

First up, we have the “CSS Clearfix method” which allows us to clear floated elements with ease.

/* Basic Styling of the Body */
body {
  background: #e0e0e0 url(/demo/responsive-nav/img/background.png);
  margin: 0 auto;
  color: black;
  text-align: center;
  font-family: "Lato", Helvetica, Arial, sans-serif;
  font-weight: 300 !important;
  font-size: 10px;
  position: relative;
  overflow: auto;
  max-width: 1300px;
}
a:link,
a:visited {
  color: #666;
  text-decoration: underline;
}
a:hover,
a:active {
  color: #a67b45;
  text-decoration: none;
  outline: none;
}
a:active {
  color: #ff6000;
}

When styling the body, we are:

  • Using a background pattern that can be repeated.
  • Making Lato the default font, and falling back to Helvetica/Arial when Google Web Fonts cannot be loaded.
  • Setting the default font size to 10px. Alternatively, you can use the “62.5% technique“.
  • Setting the max-width to 1300 pixels.
/* Le Header */
header {
  padding: 20px 0;
  position: relative;
}
header h1#branding a {
  font-family: "Euphoria Script", cursive;
  font-weight: normal;
}
header h1#branding a:link,
header h1#branding a:visited {
  color: #000;
  text-decoration: none;
}
header h1#branding a:hover,
header h1#branding a:active {
  color: #a67b45;
  text-decoration: none;
}
header h2#tagline {
  text-align: center;
  font-size: 1em;
  font-weight: normal;
  text-transform: uppercase;
  color: #444;
}

Next, we are styling the header element.

  • The branding is using the fantastic Euphoria Script font from Google Web Fonts. Falls back to any cursive font that is default on the system.
  • Making the tagline uppercase and aligning to the center of the screen. This will remain consistent across all viewports.
/* The common properties in the NAV element */
header nav {
  background-color: #f8f8f8;
  background-image: -moz-linear-gradient(top, #ffffff, #ededed);
  background-image: -ms-linear-gradient(top, #ffffff, #ededed);
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#ededed));
  background-image: -webkit-linear-gradient(top, #ffffff, #ededed);
  background-image: -o-linear-gradient(top, #ffffff, #ededed);
  background-image: linear-gradient(top, #ffffff, #ededed);
  background-repeat: repeat-x;
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed', GradientType=0);
  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  font-family: "Lato", Helvetica, Arial, sans-serif;
  font-size: 1.5em;
}

/* Making sure lists have no margin/padding */
header ul#menu {
  margin: 0 !important;
  padding: 0 !important;
}

This is the crucial navigation bar. Over here, we are defining the basic style of the navigation bar that will be applicable to both the mobile and desktop resolutions. We are also using vendor-specific code for CSS3 Gradients and Box Shadow.

/* The content and footer sections */
section.content,
footer {
  padding: 10px 20px;
  background: #FFF;
  font-size: 1.5em;
  line-height: 1.5em;
  text-align: left;
  -webkit-box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.2);
  -moz-box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.2);
  box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.2);
}
footer {
  margin: 20px 0;
}

Over here, we are styling the content box and the footer. The code should be self-explanatory.

The Stylesheets: Navigation Menu for Mobile Devices

Here is what we are trying to accomplish:

Navigation Bar for Mobile Devices

Navigation Bar for Mobile Devices

Now that the basic CSS bits are done, let us move on to the CSS Media Queries.  The first CSS attached to the document that is using the Media Queries is the mobile-nav.css that is applicable to devices with widths between 320 and 1024 pixels. This stylesheet applies to a very broad spectrum of devices ranging from smartphones to iPads.

I have previously mentioned that this bit of code will be used by at least three of the target segments of the audience. So, instead of repeating the CSS, we are delegating it to a separate stylesheet document.

/* The NAV element in mobile devices */
header nav {
  display: block;
  position: fixed;
  top: 0;
  left: 0;
  zoom: 1;
  width: auto;
  text-align: left;
  height: 40px;
  width: 100%;
}

The nav element is given a fixed position on top the viewport so that it remains in place even when you scroll the page.

/* The button on the top-right */
nav .btn-navbar {
  position: fixed;
  right: 10px;
  top: 6px;
  padding: 7px 10px;
  margin-left: 5px;
  margin-right: 5px;
  -webkit-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);
  -moz-box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);
  box-shadow: inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);
}
nav .btn-navbar:active {
  background-color: #e6e6e6;
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#d9d9d9), to(#ffffff));
  background-image: -webkit-linear-gradient(top, #ffffff, #d9d9d9);
  background-color: #d9d9d9;
  background-image: -moz-linear-gradient(top, #d9d9d9, #ffffff);
  background-image: -ms-linear-gradient(top, #d9d9d9, #ffffff);
  background-image: -o-linear-gradient(top, #d9d9d9, #ffffff);
  background-image: linear-gradient(top, #d9d9d9, #ffffff);
  background-repeat: repeat-x;
}
nav .btn-navbar .icon-bar {
  display: block;
  width: 18px;
  height: 2px;
  background-color: #000;
  -webkit-border-radius: 1px;
  -moz-border-radius: 1px;
  border-radius: 1px;
  -webkit-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
  -moz-box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.25);
}
nav .btn-navbar.active .icon-bar {
  background-color: #a67b45;
  -webkit-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25);
  -moz-box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25);
  box-shadow: inset 0 1px 0 rgba(0, 0, 0, 0.25);
}
.btn-navbar .icon-bar + .icon-bar {
  margin-top: 3px;
}

The button on the top-right corner is given a fixed position and sprinkled with some CSS3 Inset Box Shadow for looks. The icon-bar elements are designed to emulate the look of native buttons. This bit of the code is borrowed from Bootstrap and modified to fit the needs.

Next up, we are going to style the navigation menu itself. The menu would reveal itself when the top-right button is clicked/touched. However, before we get into the behaviour manipulation with Javascript, let us style the menu.

/* Using the touch scrolling on capable devices. */
.overthrow-enabled .overthrow {
  overflow: auto;
  -webkit-overflow-scrolling: touch;
}

A noticeable line in the code is the -webkit-overflow-scrolling: touch;. This is for “Native Momentum Scrolling” on iOS devices.2

We are taking advantage of the Overthrow library that enables overflow scrolling on few devices using a polyfill and gracefully degrades on non-supporting devices.

/* The unordered list with the menu */
ul#menu {
  background: #000;
  display: none;
  position: absolute;
  top: 40px;
  left: 0;
  width: 100%;
  font-size: 15px !important;
  overflow-x: hidden;
  -ms-overflow-x: hidden;
  -webkit-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  -moz-box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.5);
}
ul#menu li {
  display: block;
  height: 40px;
  width: 100%;
  border-bottom: 1px solid #ccc;
  background-color: #ededed;
  background-repeat: repeat-x;
  background-image: -moz-linear-gradient(top, #ffffff, #ededed);
  background-image: -ms-linear-gradient(top, #ffffff, #ededed);
  background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #ffffff), color-stop(100%, #ededed));
  background-image: -webkit-linear-gradient(top, #ffffff, #ededed);
  background-image: -o-linear-gradient(top, #ffffff, #ededed);
  background-image: linear-gradient(top, #ffffff, #ededed);
  filter: progid:dximagetransform.microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed', GradientType=0);
}
ul#menu li:last-child {
  border: none;
}
ul#menu li.hasChildren {
  height: auto !important;
}
ul#menu li.hasChildren ul {
  display: none;
  margin: 0 !important;
  padding: 0 0 0 20px !important;
}
ul#menu li.hasChildren ul li {
  background: none;
}
ul#menu li a {
  display: block;
  text-decoration: none;
  padding: 12px 10px;
  font-weight: normal;
}
ul#menu li a span {
  display: block;
}
ul#menu li a:link,
ul#menu li a:visited {
  color: #666;
  text-decoration: none;
  outline: none;
}
ul#menu li a:hover,
ul#menu li a:active {
  color: #a67b45;
  text-decoration: none;
  outline: none;
  background: rgba(0, 0, 0, 0.05);
}
ul#menu li.hasChildren a > span {
  background: url(/demo/responsive-nav/img/sprite.png);
  background-position: right -97px !important;
  background-repeat: no-repeat;
}
ul#menu li.hasChildren a:hover > span,
ul#menu li.hasChildren.hover > a span {
  background-position: right -138px !important;
}

The menu itself is a quite simple dropdown. A few noteworthy bits of the code are:

  • The menu is positioned just below the bar.
  • The menu takes 100% of the width of the viewport.
  • Due to the fact that, in some devices, a horizontal scrollbar appears, we have used overflow-x: hidden;  and its Mobile IE counterpart.
  • The list items have CSS3 Gradients that is supported by most modern mobile browsers. Otherwise, it falls back to a light shade of grey.

All is done with the mobile navigation. But a few problems remain:

  • The menu requires a fixed height for the overflow scroll to work. But how do you apply a fixed height on a menu that can vary in height?
  • We have styled the navigation menu, but how do we make it appear on screen?

The answer to both is: Javascript, of course.

The Javascript: Behaviour Layer that does the Magic

After the javascript behaviour is applied, here is what it should look like on mobile devices:

Expanded View of the Navigation

Interactive Button and Expanded View of the Navigation

All custom Javascript code is going into the script.js file.

We are going to reuse the jQuery plugin developed for the “Bulletproof CSS3 Dropdown Navigation Menu” as it is essential for both the desktop and mobile navigation layouts. Here is the custom plugin once again, for your convenience:

/*
* jquery.dropdown.js
* Apply sexy dropdowns on any ul with child ul.
* Depends on: jquery.hoverIntent.js
*/

$.fn.dropdown = function(options) {
var defaults = {};
  var opts = $.extend(defaults, options);

  // Apply on those items with children
  this.each(function() {
    $(this).find('li').each(function() {
      if($(this).find("ul").length > 0) {
        $(this).addClass("hasChildren");
        $(this).find('> a').wrapInner("<span></span>");
      }
    });
  });

  // Apply on all list items
  $(this).find("li").on('hover', function() {
    $(this).addClass('hover');
  }, function() {
    $(this).removeClass('hover');
  });
};

Here is what the plugin accomplishes:

  • Find the list items with children, adds the class ‘hasChildren’ and also adds a span to wrap the anchor for styling purposes.
  • Adds the class ‘hover’ when the list items are hovered upon.

Now that the plugin is done, let us go further into the script.

$(function() {

  // Calling the jquery dropdown
  $('nav').dropdown();

  /*
  * Applicable only to Mobile-nav
  */

  // Checking if the top-right button is visible.
  if ($("nav a.btn-navbar").is(":visible")) {

    // Making the dropdown magically appear onclick/touch.
    $('nav a.btn-navbar').on('click', function() {
      $('ul#menu').slideToggle('fast', function() {
        $('ul#menu').css({

        // The height must be fixed for the native-scrolling on iOS
        'height': $(this).height(),

        // But we don't want the height of the nav to exceed the viewport.
        'max-height': $(window).height() + 20
        });
      });

      $(this).toggleClass('active');

    }); // end on.click

    // Making the children appear on click/touch
    $('ul#menu li.hasChildren a').on('click', function() {
      $(this).parent().children('ul').slideToggle('fast', function() {

          $('ul#menu').css({

          // Resetting the height to auto in order to expand/contract the menu upon interaction.
          'height': 'auto',

          // But we don't want the height of the nav to exceed the viewport.
          'max-height': $(window).height() + 20
          });

        }); // end slideToggle
    }); // end on.click

 } // end visibility check

});

The code above accomplishes the following:

  • Firstly, we are calling the jQuery function that was provided a little earlier onto the nav element.
  • Checking to see if the btn-navbaris visible on screen. If it is visible, it would mean that the mobile-nav is active.3
    • Once it is established that the mobile-nav is indeed what the user is experiencing, there is a ‘click’ event on the button that toggles the unordered list.
    • Once the animation for slideToggle is complete, we are defining the height of the menu. This is because native-scrolling on iOS devices only work on objects with a fixed height.
    • Next, we are ensuring that the height of the menu does not exceed the viewport by setting a max-height.
    • Next up, there is another ‘click’ event that makes sure the list items with children can expand and contract on click/touch.
    • The height of the entire menu is reset once the user expands/contracts a list item.

With this layer of Javascript, we now have a complete navigation menu – completely optimised for the mobile viewport.

The Stylesheets: Smartphones

This is what the mobile navigation will look like in smartphones:

Responsive Navigation in a Smartphone

Responsive Navigation in a Smartphone

The smartphones with a horizontal resolution between 320 and 480 pixels will be provided with a few unique interface features such as:

  • The branding will be a part of the floating navigation bar at the top.
  • The tagline will be larger and vertically spaced between the navigation and the content.
  • The content will have a high line-height, in order to enhance readability.
header h1#branding {
  position: fixed;
  top: -15px;
  left: 10px;
  font-size: 2.5em;
  z-index: 1000;
}

header h2#tagline {
  font-size: 2em;
  line-height: 1.5em;
  margin: 40px 0 0 0;
}

section.content p {
  line-height: 2em;
}

This concludes the content of smartphone.css.

The Stylesheets: Small Tablets and the iPad

Here is what it looks like on iPad and other tablets:

Responsive Navigation Menu on iPad (in Portrait Orientation)

Responsive Navigation Menu on iPad (in Portrait Orientation)

The stylesheets tablet.css and ipad.css covers the device in both portrait and landscape orientations as we have not stipulated any orientation in the Media Queries. As there is litte difference between tablet.cssand ipad.css, I have not repeated the code:

header h1#branding {
  font-size: 4em;
  z-index: 1000;
  margin: 40px 0 0 0;
}
header h2#tagline {
  font-size: 1.7em;
  margin: 15px 0 5px 0;
}

On tablet devices, the logo is much larger and positioned below the navigation bar. The tagline is positioned below the logo. However, on smaller tablets, the line-height of the text is slightly larger in order to increase readability:

section.content p {
 line-height: 1.8em;
 }

If you have a sidebar in your design, maybe you would like to have it placed at the bottom of the content intablet.css. On the other hand, the sidebar can be placed on the right hand side on the iPad. The structure of the stylesheets allows us to craft variations in the design.

The Stylesheets: Desktop

Our final target segment of the audience is the desktop. These are users with viewports of horizontal resolution of 1025 pixels or higher. This covers almost all modern laptops, desktops and internet-plugged televisions.

Here is what the desktop users experience:

Responsive Navigation on Desktop and Larger Devices

Responsive Navigation on Desktop and Larger Devices

The navigation presented to desktop users is vastly different from the mobile experience. This is a very common suckerfish navigation menu that desktop users are very much accustomed to.

The code below is vastly similar to the “Bulletproof CSS3 Dropdown Navigation Menu” tutorial I published in January 2012.

html {
  overflow: hidden;
}
.btn-navbar {
  display: none;
}
header {
  margin: 0 auto 20px auto;
  padding: 0 5px;
}

Firstly, we take care of the horizontal scrolling problem in older versions of IE with overflow: hidden applied to the html element. Next, we make sure the top-right button does not appear on desktop screens. Also, we place the header in the center of the screen using margins.

header h1#branding {
  font-size: 4em;
  margin: 10px 0 0 0;
}
header h2#tagline {
  font-size: 1.7em;
  margin: 15px 0 5px 0;
}
section,
footer {
  margin: 20px 5px;
}

The branding is given an appropriate size and aligned appropriately. The position and size of the tagline is also adjusted. Now let us get to the tasty navigation part.

nav {
  *zoom: 1;
  margin: 20px auto 0 auto;
  width: auto;
  text-align: left;
}
nav:before,
nav:after {
  display: table;
  content: "";
}
nav:after {
  clear: both;
}

Keeping in mind that the nav element would inherit some styles (such as gradient and font) from atmosphere.css, we can march on with the design on the desktop. The navigation is aligned to the center of the screen. We are also applying the :before and :after pseudo-class clearing technique.

nav ul {
  float: left;
  *zoom: 1;
  width: auto;
  z-index: 100;
  font-size: 15px;
  border-right: 1px solid #e8e8e8;
}
nav ul:before,
nav ul:after {
  display: table;
  content: "";
}
nav ul:after {
  clear: both;
}

The font-size on the primary-level list is set in pixels because em makes the children inherit relative styles, making the whole design inconsistent. Hence, going forward with a pixel-based size suites best.

nav ul li {
  float: left;
  padding: 0 0 10px 0;
  position: relative;
  outline: none;
  line-height: 1.2em;
  padding: 0 1px 0 0;
  border-left: 1px solid #e8e8e8;
  list-style: none;
}
nav ul li.hasChildren a span {
  padding: 0 20px 0 0;
  background: url(/demo/responsive-nav/img/sprite.png);
  background-position: right top;
  background-repeat: no-repeat;
  display: block;
}
nav ul li.hasChildren a:hover span,
nav ul li.hasChildren.hover a span {
  background-position: right -50px;
}

The list items are floated to the left and positioned as you would find in a regular suckerfish dropdown navigation. The items that have nested lists are given the class “hasChildren” by the javascript library are now being styled.

nav ul a {
  padding: 15px 20px 15px 20px;
  font-weight: normal;
  float: left;
  display: block;
  zoom: 1;
}
nav ul a:link,
nav ul a:visited {
  color: #666;
  text-decoration: none;
  background-color: #f8f8f8;
  background-image: -moz-linear-gradient(top, #ffffff, #ededed);
  background-image: -ms-linear-gradient(top, #ffffff, #ededed);
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#ededed));
  background-image: -webkit-linear-gradient(top, #ffffff, #ededed);
  background-image: -o-linear-gradient(top, #ffffff, #ededed);
  background-image: linear-gradient(top, #ffffff, #ededed);
  background-repeat: repeat-x;
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffff', endColorstr='#ededed', GradientType=0);
  -webkit-transition: all 0.3s ease;
  -moz-transition: all 0.3s ease;
  -ms-transition: all 0.3s ease;
  -o-transition: all 0.3s ease;
  transition: all 0.3s ease;
  outline: none;
}
nav ul a:hover,
nav ul a:active {
  color: #a67b45;
  text-decoration: none;
  background-color: #f4f4f4;
  background-image: -moz-linear-gradient(top, #ededed, #ffffff);
  background-image: -ms-linear-gradient(top, #ededed, #ffffff);
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ededed), to(#ffffff));
  background-image: -webkit-linear-gradient(top, #ededed, #ffffff);
  background-image: -o-linear-gradient(top, #ededed, #ffffff);
  background-image: linear-gradient(top, #ededed, #ffffff);
  background-repeat: repeat-x;
  filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ededed', endColorstr='#ffffff', GradientType=0);
  -webkit-transition: all 0.1s ease;
  -moz-transition: all 0.1s ease;
  -ms-transition: all 0.1s ease;
  -o-transition: all 0.1s ease;
  transition: all 0.1s ease;
  outline: none;
}
nav ul a:active {
  -webkit-box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.3) inset;
  -moz-box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.3) inset;
  box-shadow: 0 0 3px 1px rgba(0, 0, 0, 0.3) inset;
}

The anchor links are given CSS3 Gradient backgrounds. The :hover and :active states have an inverted gradient. Also, the inset Box Shadow on the :active state gives the list items some visual depth.

#menu li:hover > ul {
  display: block;
}
#menu li:hover > a {
  color: #a67b45;
}

This is the “switch” that makes the nested list appear when you hover on an item. Since we are using Selectivizr in our document, we can safely apply :hover pseudo-class on the list.

nav li ul {
  display: none;
  margin: 0;
  position: absolute;
  top: 46px;
  left: 0px;
  width: 130px;
  border: none !important;
  padding: 2px;
  background: #999;
  z-index: 1000;
  *zoom: 1;
  -webkit-box-shadow: none;
  -moz-box-shadow: none;
  box-shadow: none;
}
nav li ul:before,
nav li ul:after {
  display: table;
  content: "";
}
nav li ul:after {
  clear: both;
}
nav li ul a {
  float: none;
}
nav li ul li {
  width: 130px;
  display: block;
  border-top: 1px solid #cfcfcf;
  border-left: none !important;
}
nav li ul li.hasChildren a > span {
  background: url(/demo/responsive-nav/img/sprite.png);
  background-position: right -97px !important;
  background-repeat: no-repeat;
}
nav li ul li.hasChildren a:hover > span,
nav li ul li.hasChildren.hover > a span {
  background-position: right -138px !important;
}

The code presented here is the CSS for the child lists. They are positioned in relation to their parent. The floats have been taken away from the list items and they are now block elements with a fixed width of 130 pixels.

.rgba nav li > ul {
  padding: 10px;
  left: -10px;
  background: rgba(0, 0, 0, 0.1);
  -webkit-border-radius: 10px;
  -moz-border-radius: 10px;
  border-radius: 10px;
}
nav li ul li ul {
  display: none;
  left: 130px !important;
  top: -3px;
}
.rgba nav li ul li ul {
  top: -10px;
}
.rgba nav li > ul {
  margin-top: -1px;
}

We are taking advantage of Modernizr to provide enhancements to the navigation on modern browsers. Browsers with rgba support would be provided with a transparent rounded border around the dropdowns that creates a nice visual effect. Go ahead the read the “Bulletproof CSS3 Dropdown Navigation Menu” article for a complete rundown on the development of this progressively enhanced menu.

That concludes the code for desktop.css.

With that, we have concluded the development of the navigation menu using the mobile-first approach. Try out the “demonstration site” and test using mobile/tablet devices.

Get the full access to source code which is “available at Github”.

Limitations

The solution provided above is not without limitations. The first and foremost being that the entire design is non-functional without Javascript. Unlike Roger Johansson’s solution, there is no fallback to a simple list in the absence of Javascript.

I have also spotted some irregular behaviour with the dropdowns whilst browsing with the iPhone that could not be traced and debugged. On the iPhone 4, there is a tendency to freeze when there is too many nested lists.

Also, the javascript code presented here uses the ‘click’ event which is not optimal for mobile devices. The ‘click’ event is significantly slow on MobileSafari (and other mobile browsers) in comparison to mobile-friendly events found in jQuery MobilejQMobi and jQTouch.

There may be other limitations and pitfalls that I am not aware of. All I can say is that this demonstration is highly experimental and probably not ready for production use.

Further Reading

Web design gurus from all over the world have written articles regarding responsive web design that are worthy reads:

Useful Resources

Some of the resources used in this demonstration in addition to some really interesting web development tools and tips:

Conclusion

Learning the Mobile First approach will change your entire mindset towards the web design and the development process. It allows us to focus on the content and prioritise the essential elements over superflous visuals.

Focusing on a responsive navigation is simply the stepping stone towards delivering greater user experiences, in terms of navigability, to users from a vast array of devices.

A disclaimer: At the time of writing, this website is not responsive itself. The responsive version of the site is currently in the over and may take some time to bake. In this article, I have simply shared what I learned whilst developing responsive web designs for clients.

I hope you enjoyed the tutorial and please do share your thoughts in the comment section below.

 

Fonte: http://azadcreative.com/2012/07/responsive-mobile-first-navigation-menu/

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s