Mobile App Design and Dev: Building Navigation with jQuery

Smartphones are now equipped with some very efficient web browsers. JavaScript is more powerful than ever before and can be extended with the help of code libraries such as jQuery. When you add in the latest HTML5/CSS3 specs, it’s possible to build very snappy mobile web apps with some basic frontend code.

In this tutorial I’ll show how you can build a mobile-based website/webapp. We’ll use CSS3 media queries for targeting specific devices and screen resolutions. Plus a bit of jQuery helps to animate the menu and load external page content using Ajax calls. Even better, the layout can even expand to display properly in regular desktop browsers such as Chrome or Firefox.

Defining the Page Structure

Let’s start by going over the HTML page first and style it using some CSS rules. I’ll skip over most of the unusual meta tags in the header since they don’t affect the web app directly. However, there are a few I should mention, namely from the snippet below:

<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">

X-UA-Compatible is used to describe how your document should render in certain browsers. It’s an interesting scenario when coding in HTML5, so I wouldn’t worry too much about this. However the meta viewport tag is very important. It sets the mobile browser window to 100% instead of the standard zoomed effect.

It’s also possible to disable user zoom with the content value user-scalable=no. But in this case, we just want to set the full-screen width to be the same as our device width. The Apple web app tags will allow the website to be saved as a home screen icon to your iPhone or iPod Touch. Not totally necessary but certainly worth having.

Inner Body Content

Inside the body tag I’ve setup a wrapper div with the ID #w. Inside I’ve broken the layout into two more divs using IDs #pagebody and #navmenu. The whole page width is limited to 640px by choice so that the layout scales to a strict number.

<div id="pagebody">
	<header id="toolbarnav">
		<a rel="nofollow" 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 rel="nofollow" href="#homepage.html" class="navlink">Home</a></li>
		 <li><a rel="nofollow" href="#about.html" class="navlink">About Us</a></li>
		 <li><a rel="nofollow" href="#advertise.html" class="navlink">Advertise</a></li>
		 <li><a rel="nofollow" href="#write.html" class="navlink">Write for Us</a></li>
		 <li><a rel="nofollow" href="#contacts.html" class="navlink">Contacts</a></li>
		 <li><a rel="nofollow" href="#privacy.html" class="navlink">Privacy Policy</a></li>
		</ul>
</div>

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 over 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 would 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 a whole lot of confusing content inside our CSS code. Most of the positioning is done manually and then manipulated through jQuery. But there are a few interesting pieces in our document.

/** @group core body **/
#w #pagebody {
	position: relative;
	left: 0;
	max-width: 640px;
	min-width: 320px;
	z-index: 99999;
}

#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, so this leaves a bit of room for the page content to still be seen. The open/close menu button is also located directly on the left side and always accessible. The important piece here is the z-index property value and using position: fixed; on our navmenu.

The top toolbar header is also an interesting section. This 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; 
	-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 I’m also using a background image for the blue header bar texture. This is sized at 640×44 pixels to keep with the consistent layout structure. But I’ve also developed an image @2x for iPhone/iPad retina displays. You can see both of the images below, or grab them from my demo source code.

I setup the mobile CSS for this functionality in another file named responsive.css. It contains two media queries which replace the title bar bg 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 over to the right side of each menu link. This can easily be replaced with an image from any creative commons artwork. But mostly all CSS3 aficionados will love 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. I also setup position: absolute; so we can freely move these borders around the inner link item. It’s super easy to change the border color on a hover state, which offers a more dynamic feeling. It’s pretty incredible what you can accomplish just by using basic HTML5 and CSS3 rules.

But now let’s move into the bits and pieces of JavaScript code. Remember this require an include to the jQuery library for my code to run properly.

jQuery Animated

In writing these custom codes I’ve created a brand new document named script.js. Feel free to 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 setup some page variables where we can reference elements in the document much quicker. The viewport value is never used, but it can be useful if you wish to adjust the animation stages. For example, you can check the current browser width and open your menu smaller or wider accordingly.

function openme() { 
	$(function () {
	  topbar.animate({
	    left: "290"
	  }, { duration: 300, queue: false });
	  pagebody.animate({
	    left: "290"
	  }, { duration: 300, queue: false });
	});
}

function closeme() {
	var 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 and callback toggle – except we actually need to animate two distinct elements at the same time. Unfortunately, this isn’t the default behavior for jQuery so we need to resort to 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 we have the title bar position fixed to the top of the page. This means it won’t naturally animate with the page and we need to use a separate call. The opening is setup to push 290px left (almost the full 300px nav width) and the closing function retracts it.

Loading Dynamic Content

The code above is easy enough to take care of the animation. And theoretically, that’s all you need for such a simple mobile website – but I want to add a tiny bit more.

Each time the user clicks on a menu link, we want to close the current navigation and display a loading gif while we look for the page content. Then once completed we remove the gif image and load it all inside. This is fantastic because we can even use static .html pages for the content. No PHP or Ruby or Perl or any backend languages to make things messy.

Managing Clicks

First off we want to test when our users click on the navigation buttons. This will stop the normal href value from loading and we can instead use our own 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>';

Now we’re 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 pieces to this effect which I’ve neatly broken up. The code below is our first bit which closes the navigation menu and slides the total document window all the way to the top. We want to replace the inner body content with a small loader animation, and users can’t see this if they were looking at the bottom of the page.

closeme();
	
$(function() {
	topbar.css("top", "0");
	window.scrollTo(0, 1);
});

Now finally we want to replace the inner body content with our image and fetch the external page to load. Normally this will only take a couple hundred milliseconds or even faster, so I’ve set a timeout function.

content.html(imgloader);
	
setTimeout(function() { content.load(linkhtmlurl, function() { /* no callback */ }) }, 1200);

This will pause 1200 milliseconds before loading new content. For my demo this looks a lot better and gives you an idea of how the application would behave on slower Internet connections.

mobile web app HTML5/CSS3/jQuery tutorial - live demo

Conclusion

I encourage all web developers to download the tutorial source code and play around on their own. This is such 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.

See if you can apply any of this code in your future web projects. Building mobile applications is an art, much like web design, and requires a lot of dedication and practice. I hope this tutorial can be a good starting point for just a few enthusiastic developers. If you have questions or thoughts about the code feel free to share with us in the post-discussion area.

WebsiteFacebookTwitterInstagramPinterestLinkedInGoogle+YoutubeRedditDribbbleBehanceGithubCodePenWhatsappEmail