Recreate Google Nexus Menu

Recreate Google Nexus Menu


Recreate Google Nexus Menu

Recently I stumbled upon Codrops' tutorial regarding the recreation of Google Nexus navigation menu. That was inspiring and such a creative navigation system from Google. So, I decided to create a jQuery version to challenge to myself.

I have been playing with the original Google Nexus Menu for a while. Based on my observation, I summarised its behaviour as below:

  • When hovering over the menu button, it will show icon only menu. And when you click on it, it will show full menu.
  • When it's showing icon only menu, the menu will hide itself on mouse out. Whereas when it's showing full menu, it won't hide itself until you click on the web page.
  • Icon only menu won't display secondary menu. Secondary menu will expand in full menu.
  • It uses mobile touchstart event and also responsive.

Now we understand its characteristics, and it will be much more easier to code it. It's not 100% imitation but it captured the essence of Google Nexus menu. Below is the screenshot of the final result:

One thing though, since it's coded with CSS3, as a result, it only works in browsers that support CSS3 transition.A pure Javascript version is possible, but I have decided to embrace the new technology :)

HTML

As you can see, we will have to build two menus, and add interactions and animation transitions on them. The structure of the menu is really straight forward and standard. We are using UL list for both.

Main Nav

<nav>
	<ul>
		<li><a href="#" class="icon icon-menu" id="btn-menu">Menu</a></li>
	</ul>
</nav>

Side Nav

<div id="sideNav">
	<ul>
		<li class="searchForm">
			<a href="#" class="icon icon-search">
				<span>
					<input type="text" placeholder="Search" class="search" />
				</span>
			</a>
		</li>
		<li><a href="#" class="icon icon-home"><span>Parent</span></a>
			<ul>
				<li><a href="#"><span>Children</span></a></li>
			</ul>
		</li>
	</ul>	
</div>	

CSS

We use fair a bit of CSS3 feature here such as transition, box-sizing and responsive layout. We will be using CSS3 transition to animate everything to take the advantage of GPU. I just reckon CSS3 animation is smoother than Javascript.

We put everything that need CSS transition together.

#sideNav,
#sideNav.showHalfMenu,
#sideNav.showFullMenu,
#sideNav ul ul li,
#sideNav.showFullMenu ul ul li	 {
	-webkit-transition: 0.2s ease;
	-moz-transition: 0.2s ease;			
	-ms-transition: 0.2s ease;						
	transition: 0.2s ease;		
}	

And the rest of the styling for the menu.

html.cursor {
	cursor: pointer;
}

nav {
	font-family: 'Roboto', sans-serif;
	width: 100%;
	height: 59px;
	border-bottom:1px solid #ddd;
	position: fixed;
	top:0;
	left:0;
	z-index:20;
	background-color:#ffffff;
}

	nav ul,
	#sideNav ul,
	#sideNav ul ul	{
		margin:0;
		padding:0;
		list-style:none;
	}
	
		nav li {
			margin:0;
			float:left;
			border-right:1px solid #ddd;
			font-size:18px;
		}
		
		nav a,
		#sideNav a {
			color:#5b6064;
			text-decoration:none;
			display:block;
			padding:10px 30px;
			height:59px;
			-webkit-box-sizing: border-box;
			-moz-box-sizing: border-box;
			-o-box-sizing: border-box;
			line-height:35px;
		}
		
		nav a:hover,
		#sideNav a:hover {
			color:#ffffff;
			background-color: #5b6064;
		}	
		
	#sideNav {
		position: fixed;
		left:-60px;
		top:59px;
		width: 60px;
		height:100%;
		border-right:1px solid #ddd;						
		background-color:#ffffff;
		overflow-y: auto;	
	}
		
		#sideNav.showHalfMenu {
			left:0;			
		}
		
		#sideNav.showFullMenu {
			left:0;
			width: 311px;		
		}

			#sideNav.showFullMenu ul ul li {
				height:59px;				
			}	
	
	
		#sideNav > ul {
			width: 100%;		
			padding-bottom:60px;	
		}
	
		#sideNav ul li {
			width: 100%;
			margin:0;		
			font-weight:300;
		}
		
		#sideNav ul li a {
			border-bottom:1px solid #ddd;		
			padding-left:70px;
		}
		
		#sideNav ul li span {
			position: relative;
			top:3px;
		}		
		
		#sideNav ul ul li {
			overflow:hidden;
			height: 0;				
		}
				

Search

One of the features of the menu is, the first menu item of the side nav has a search field that blended into the menu. Not sure if it's a good practice but it does look sleek. This is where I picked up another new thing, we actually allow to change placeholder color!

		#sideNav input.search {
			font-family: 'Roboto', sans-serif;			
			border:0;
			outline:0;
			font-weight:300;
			background:transparent;
			color:#5b6064;			
		}

				
		input.search::-webkit-input-placeholder {
			color:#5b6064;		
		}
		input.search:-moz-placeholder {
			color:#5b6064;		
		}
		input.search::-moz-placeholder {
			color:#5b6064;		
		}
		input.search:-ms-input-placeholder {
			color:#5b6064;
		}
		
		#sideNav li.searchForm:hover input.search:focus,
		#sideNav li.searchForm:hover input.search::-webkit-input-placeholder {
			color:#fff;		
		}		

Responsive

Not much here, we just want the menu fit well on mobile. It will look like this:

@media only screen and (min-width: 200px) and (max-width: 480px) {

	nav a,
	#sideNav a {
		padding:10px 15px;
	}	
	
	nav a#btn-menu {
		padding:10px 30px;	
	}

	#sideNav.showFullMenu,
	#sideNav.showFullMenu li,
	#sideNav.showFullMenu	a	 {
		width: 100%;
	}    

}

Javascript

And... the last section. Animation is just a matter of applying the right CSS classes at the right spot. We created a few functions such as showHalfMenu(), showFullMenu(), hideMenu() and toggleMenu so we can reuse them.

We also put in a mobile detection script I found from stackoverflow to make sure touch screen devices don't have to load desktop mouse events.

As usual, I added inline comments in the script to show how it's done.

$(function () {
	
	var GNmenu = {
		isMenuOpened: false,
		init : function () {

			var menuBtn = $('#btn-menu');
			
			// make it work on touch screen device and mouse click
			menuBtn.on('touchstart click', function (e) {
				e.stopPropagation();
				e.preventDefault();
				
				/* if the menu is half show, show the whole menu instead of hide it */
				if ($('#sideNav').hasClass('showHalfMenu') && !$('#sideNav').hasClass('showFullMenu')) {
					GNmenu.showFullMenu();
				} else {
					GNmenu.toggleMenu();												
				}
				
			});

			// only do all this if it's desktop
			if (!GNmenu.isMobile()) {

				menuBtn.bind('mouseover', function () {
						GNmenu.showHalfMenu();
				});
				
				menuBtn.bind('mouseout', function () {
						GNmenu.hideMenu();
				});	
			
				$('#sideNav').bind('mouseover', function () {
						GNmenu.showFullMenu();
				});											

				// this allow user to hide the menu by clicking on web page body
				GNmenu.bodyClick();
			}
						
			// search form
			// unbind the bodyClick event 
			$('.searchForm input[type=text]').focus(function () {
				$('html').unbind('click');	
			}).blur(function() {
				GNmenu.bodyClick();												
			});
													
		},
		
		bodyClick: function () {
		
			$('html').bind('click',function () {
				if (GNmenu.isMenuOpened) {
					GNmenu.hideMenu();														
				}
			});					
		
		},
		
		toggleMenu: function () {
			if (!GNmenu.isMenuOpened) {
				GNmenu.showFullMenu();
			} else {
				GNmenu.hideMenu();					
			}
		},
		
		showHalfMenu: function () {
			$('#sideNav').addClass('showHalfMenu');
			GNmenu.isMenuOpened = true;					
		},
		
		showFullMenu: function () {
			$('#btn-menu').addClass('icon-menu-active');
			$('#sideNav').addClass('showFullMenu');
			$('html').addClass('cursor');				
			GNmenu.isMenuOpened = true;							
		},
		
		hideMenu: function () {
			$('#btn-menu').removeClass('icon-menu-active');
			$('#sideNav').removeClass('showFullMenu showHalfMenu');		
			$('html').removeClass('cursor');						
			GNmenu.isMenuOpened = false;					
		},
		
		// Mobile Detection: http://stackoverflow.com/a/11381730				
		isMobile: function() {
			var check = false;
			(function(a){if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
			
			return check; 					
		}
		
	}
	
	// Run the Google Nexus Inspired Menu
	GNmenu.init();
	
});	

Conclusion

It's not hard to replicate something from sketch. What we need to do is to understand its behavior. Also, get your web developer tools ready, you will need to do a lot of code inspections for better understanding of how it works.

We just recreated a replica of Google Nexus menu with jQuery library. If you preferred something standalone, read tutorial from Codrops by Mary Lou, she did it without jQuery library.

Drop us a comment if you have any questions and stay tuned with us for more posts like this.

Author: Kevin Liew

Kevin Liew is a web designer and developer and keen on contributing to the web development industry. He loves frontend development and absolutely amazed by jQuery. Feel free to say hi to me, or follow @quenesswebblog on twitter.

Share the love

6 comments

atal
Tue, 17th September 2013
how you will highlight this menu if we are in particular section Reply
Eddie Givens
Tue, 17th September 2013
Thank you for posting things! This is exactly what I was looking for on a project I'm working on. Thanks! Reply
Nick
Wed, 6th November 2013
Well i was searching for the same answer but doesn't get the exactly result of the same. As of for the alternative i just hired http://www.markupcloud.com and i got the answer for the problem. Frankly speaking they are best at designing aspects. You can easily rely on them. Reply
Sanjeev
Sun, 8th December 2013
Thanks for the article/tutorial/plugin. This is much easier to follow thean the others. I'll use it.
One modification, we can use font-awesome icons instead.

Add CSS
<link href="//netdna.bootstrapcdn.com/font-awesome/4.0.3/css/font-awesome.css" rel="stylesheet">

Remove default icon [class="icon icon-xxxx"]
Add icon <i class="fa fa-location-arrow fa-2x fa-fw"></i> instead

Update CSS to add padding to menu text.
.sidebar-text {
padding-left:50px;
}

Reply
reyrey
Thu, 2nd January 2014
sorry can you tell me what will do use like this {if(/(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od)|iris|kindle|lge |maemo|midp|mmp|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows (ce|phone)|xda|xiino/i.test(a)||/1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-/i.test(a.substr(0,4)))check = true})(navigator.userAgent||navigator.vendor||window.opera);
Reply
ella
Sun, 16th February 2014
great tutorial! i've been looking for this version of mary lou's (codrops), thanks a lot! cheers! Reply

Leave a Comment

Please keep in mind that comments are moderated and rel="nofollow" is in use. You can use [code][/code] if you want to write codes. Don't spam us :) Thanks!

Advertisement