Building Efficient Mobile Navigation with jQuery
Smartphones now come with highly efficient web browsers. JavaScript has become more powerful than ever and can be extended with the help of code libraries like jQuery. Combined with the latest HTML5/CSS3 specifications, it’s possible to build fast and responsive mobile web apps with basic frontend code.
In this tutorial, I’ll show you how to build a mobile-based website or web app. We’ll use CSS3 media queries to target specific devices and screen resolutions. Additionally, we’ll use a bit of jQuery to animate the menu and load external page content using Ajax calls. Even better, the layout can expand to display correctly in regular desktop browsers such as Chrome or Firefox.
Defining the Page Structure
Let’s start by reviewing the HTML page structure and applying some CSS rules. We’ll skip most of the unusual meta tags in the header since they don’t directly affect the web app. However, the following meta tags are important:
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <meta name="apple-mobile-web-app-capable" content="yes"> <meta name="apple-mobile-web-app-status-bar-style" content="black">
The X-UA-Compatible tag describes how your document should render in certain browsers. It’s particularly interesting when coding in HTML5, though not essential to worry about too much here. However, the meta viewport tag is crucial. It sets the mobile browser window to 100% instead of the default zoomed effect.
You can also disable user zoom with the content value user-scalable=no
. In this case, we just want to set the full-screen width to match the device width. The Apple web app tags enable the website to be saved as a home screen icon on iPhones or iPod Touches. While not necessary, it’s a useful feature to have.
Inner Body Content
Inside the body tag, I’ve set up a wrapper div with the ID #w
. Within this wrapper, I’ve divided the layout into two more divs with IDs #pagebody
and #navmenu
. The entire page width is limited to 640px to ensure the layout scales consistently.
<div id="pagebody"> <header id="toolbarnav"> <a href="#navmenu" id="menu-btn"></a> <h1>HK Mobile</h1> </header> <section id="content" class="clearfix"> <h2>Welcome to the Mobile Site!</h2> </section> </div> <div id="navmenu"> <header> <h1>Menu Links</h1> </header> <ul> <li><a href="#homepage.html" class="navlink">Home</a></li> <li><a href="#about.html" class="navlink">About Us</a></li> <li><a href="#advertise.html" class="navlink">Advertise</a></li> <li><a href="#write.html" class="navlink">Write for Us</a></li> <li><a href="#contacts.html" class="navlink">Contacts</a></li> <li><a href="#privacy.html" class="navlink">Privacy Policy</a></li> </ul> </div>
#w #navmenu { background: #475566; height: 100%; display: block; position: fixed; width: 300px; left: 0px; top: 0px; z-index: 0; }
This top segment defines styles for both sections of the page. Our nav menu is only 300px wide, leaving some room for the page content to still be visible. The open/close menu button is located directly on the left side and is always accessible. The important piece here is the z-index property value and using position: fixed;
on our nav menu.
The top toolbar header is also an interesting section. It is set to a fixed position so it will scroll with the page content. This replicates a similar effect as you’d find in any iOS app title bar.
/** @group header **/ #w #pagebody header#toolbarnav { display: block; position: fixed; left: 0px; top: 0px; z-index: 9999; background: #0b1851 url('img/tabbar-solid-bg.png') top left no-repeat; border-radius: 5px; -moz-border-radius: 5px; -webkit-border-radius: 5px; -o-border-radius: 5px; border-bottom-right-radius: 0; -moz-border-radius-bottomright: 0; -webkit-border-bottom-right-radius: 0; border-bottom-left-radius: 0; }
The navigation menu is given a lower z-index value so that #pagebody
is always on top. This is crucial since the JavaScript code will slide the page body a certain number of pixels to reveal the navigation underneath.
I’ve used a hash symbol (#) in front of each .html page to stop some poor behavior in Mobile Safari. Whenever you click a link, the URL bar appears and pushes down the content. But when referencing an ID, nothing is reloaded except through JavaScript calls.
CSS Positioning
There isn’t much confusing content in our CSS code. Most of the positioning is done manually and then manipulated through jQuery. However, there are a few interesting pieces in our document.
/** @group core body **/ #w #pagebody { -moz-border-radius-bottomleft: 0; -webkit-border-bottom-left-radius: 0; height: 44px; width: 100%; max-width: 640px; } #w #pagebody header#toolbarnav h1 { text-align: center; padding-top: 10px; padding-right: 40px; color: #e6e8f2; font-weight: bold; font-size: 2.1em; text-shadow: 1px 1px 0px #313131; }
Mobile Rules
It’s easy to notice that I’m also using a background image for the blue header bar texture. This image is sized at 640×44 pixels to maintain the consistent layout structure. Additionally, I’ve created an image @2x for iPhone/iPad retina displays. You can see both images below or grab them from my demo source code:
I set up the mobile CSS for this functionality in another file named responsive.css. It contains two media queries which replace the title bar background and the menu button icon for retina devices.
/** retina display **/ @media only screen and (-webkit-min-device-pixel-ratio: 2), only screen and (min--moz-device-pixel-ratio: 1.5), only screen and (min-device-pixel-ratio: 1.5) { #w #pagebody header { background: #0b1851 url('img/tabbar-solid-bg@2x.png') top left no-repeat; background-size: 640px 44px; } #w #pagebody header #menu-btn { background: url('img/nav-btn@2x.png') no-repeat; background-size: 53px 30px; } }
Designing Menu Arrows
In the navigation area, I’ve also included a small arrow icon on the right side of each menu link. This can easily be replaced with an image from any creative commons artwork. However, most CSS3 enthusiasts will enjoy testing out this method.
#w #navmenu ul li a::after { content: ''; display: block; width: 6px; height: 6px; border-right: 3px solid #d0d0d8; border-top: 3px solid #d0d0d8; position: absolute; right: 30px; top: 45%; -webkit-transform: rotate(45deg); -moz-transform: rotate(45deg); -o-transform: rotate(45deg); transform: rotate(45deg); } #w #navmenu ul li a:hover::after { border-color: #cad0e6; }
We are using the transform
property to create a small border after the content. Additionally, position: absolute;
is used to freely move these borders around the inner link item. Changing the border color on hover offers a more dynamic feel. It’s incredible what you can achieve with basic HTML5 and CSS3 rules.
Now, let’s delve into the JavaScript code. Remember, this requires including the jQuery library for the code to run properly.
jQuery Animation
In writing these custom codes, I’ve created a new document named script.js. You can write these directly in <script>
tags, or download my example from the demo source code.
$(document).ready(function() { var pagebody = $("#pagebody"); var themenu = $("#navmenu"); var topbar = $("#toolbarnav"); var content = $("#content"); var viewport = { width: $(window).width(), height: $(window).height() }; // retrieve variables as // viewport.width / viewport.height });
To begin, I’ve set up some page variables to reference elements in the document more quickly. The viewport value is not used here, but it can be useful if you want to adjust the animation stages. For example, you can check the current browser width and adjust your menu accordingly.
function openme() { $(function() { topbar.animate({ left: "290" }, { duration: 300, queue: false }); pagebody.animate({ left: "290" }, { duration: 300, queue: false }); }); } function closeme() { $(function() { topbar.animate({ left: "0" }, { duration: 180, queue: false }); pagebody.animate({ left: "0" }, { duration: 180, queue: false }); }); }
Next, I’ve defined two important functions for opening and closing the menu. These could have been done in a single function with a callback toggle; however, we need to animate two distinct elements simultaneously. Unfortunately, this isn’t the default behavior in jQuery, so we need to use an alternative syntax.
The two elements we’re targeting are named topbar and pagebody. The inner content area with a white background is the full pagebody; however, the title bar is fixed at the top of the page. This means it won’t naturally animate with the page, so we need to use a separate call. The opening function pushes the elements 290px left (almost the full 300px nav width), and the closing function retracts them.
Loading Dynamic Content
The code above easily handles the animation. Theoretically, that’s all you need for such a simple mobile website. However, I want to add a bit more functionality.
Each time the user clicks on a menu link, we want to close the current navigation and display a loading gif while we fetch the page content. Once completed, we remove the gif image and load the new content inside. This approach is fantastic because we can use static .html pages for the content, avoiding the complexity of backend languages like PHP, Ruby, or Perl.
Managing Clicks
First, we need to detect when users click on the navigation buttons. This will prevent the default href value from loading, allowing us to use our functions to display external content.
// loading page content for navigation $("a.navlink").live("click", function(e) { e.preventDefault(); var linkurl = $(this).attr("href"); var linkhtmlurl = linkurl.substring(1, linkurl.length); var imgloader = '<center style="margin-top: 30px;"><img src="img/preloader.gif" alt="loading..."/></center>'; });
We are opening a selector for any anchor with the class navlink
. Whenever a user clicks one of these links, we stop it from loading and set up a variable for the full URL. I’ve also set up a variable for the content HTML to include a standard image loader.
Ajax .load()
There are two different parts to this effect, which I’ve neatly separated. The code below closes the navigation menu and slides the document window to the top. We replace the inner body content with a small loader animation, which users can’t see if they are at the bottom of the page.
closeme(); $(function() { topbar.css("top", "0"); window.scrollTo(0, 1); });
Finally, we want to replace the inner body content with our image and fetch the external page to load. Normally, this takes a couple of hundred milliseconds or less, so I’ve set a timeout function.
content.html(imgloader); setTimeout(function() { content.load(linkhtmlurl, function() { // callback }); }, 1200);
This pauses for 1200 milliseconds before loading new content. For my demo, this delay looks better and gives an idea of how the application would behave on slower Internet connections.
Conclusion
I encourage all web developers to download the tutorial source code and experiment on their own. This is a basic example of what can be accomplished with HTML/CSS3 and a touch of JavaScript effects. Building for mobile screens is easier than ever with media queries and more extensible web browsers.
Try to apply some of this code in your future web projects. Building mobile applications is an art, much like web design, and requires dedication and practice. I hope this tutorial serves as a good starting point for a few enthusiastic developers. If you have questions or thoughts about the code, feel free to share them in the post-discussion area.