Apple Mac Navigation

Tutorial: Create The Apple Mac Website Navigation Using Greensock [Part 1]

My first tutorial how to “Create Apple navigation using Greensock” was so popular among other front-end developers and designers, that I have decide to share another one with you today.

This time we will try to recreate the even slicker Apple Shop Mac navigation using jQuery and Greensock. Because the code is more complex than last time, I have decided to break down my explanation into two posts.

I will cover the initial function animateSlides today and the remaining updateNav and resetStage in the next post.

View Demo

Follow me @ihatetomatoes if you don’t want to miss out on the second part.

HTML/CSS

Similar to last time, I have used the default HTML5 Boilerplate as a starting point and borrowed most of the html and css from Apple’s website.

<!-- Simplified html for illustration purposes -->
<div class="productbrowser content pb-opened" id="pb-mac">
	<div class="pb-slider">
		<div class="pb-slide">
			<ul class="ul-slider" page="1">
				<li class="pb-macbookair">
					<a href="#"><img src="images/macbookair.jpg" alt="">MacBook Air</a>
				</li>
				<li class="pb-macbookpro">
					<a href="#"><img src="images/macbookpro.jpg" alt="">MacBook Pro</a>
				</li>
				...
			</ul>
			<ul class="ul-slider" page="2">
				...
			</ul>
			<ul class="ul-slider" page="3">
				...
			</ul>
			<ul class="ul-slider" page="4">
				...
			</ul>
		</div>
	</div>

	<div class="pb-pageindicator roundedbottom page-2" id="pb-pi-mac"><div>
		<b class="caret"></b> 
		<a class="page active" page="1">Mac</a> 
		<a class="page" page="2">Applications</a> 
		<a class="page" page="3">Accessories</a> 
		<a class="page" page="4">Server</a>
	</div></div>
</div>

The aim of this tutorial is to dive straight into the interactive side of things, with the assumption that you are already familiar with well structured HTML and CSS code.

jQuery – Greensock

All the magic happens in main.js and we will use jQuery for selecting our objects and Greensock for the animations.

1. Setup variables and functions

$(document).ready(function() {

	var slide = $('.ul-slider'),
		navigationLinks = $('.pb-pageindicator a'),
		activeNavLink = $('.pb-pageindicator a.active'),
		navArrow = $('.caret');
	
	$(productbrowser).addClass('pb-dynamic'); 
	$(slide).not('.ul-slider:eq(0)').hide(); //hide all slides apart from 1st one
	$(slide).eq(0).addClass('active'); //add active class

	/* Navigation - click stuff */
	$(navigationLinks).click(function() {
		animateSlides(this);
	});

	/* Slides Animation - magic */
	function animateSlides(e){
		
	}
	
	/* Update Nav - animate the little man */
	function updateNav(e, pageID){

	}
	
	/* Reset Stage - clear the table */
	function resetStage(e){

	}
	
});

We setup our variables and functions which we will need later on. We are also hiding all slides apart from the active one on page load.

2. Slides Animation Setup

	/* Slides Animation */
	function animateSlides(e){
		
		$(navigationLinks).unbind('click');
		
		var pageID = $(e).attr('page'),
			slideIn = $(".ul-slider[page='" + pageID + "']"),
			slideOut = $('.ul-slider.active'),
			products = $($(slideOut).find('li').get()),
			slideInProducts = $($(slideIn).find('li').get()),
			tl = new TimelineMax({onStart:updateNav, onStartParams: [pageID], onStartScope: e, onComplete:resetStage, onCompleteScope: e});
		
		$(slideIn).show();
		$(navigationLinks).removeClass('active');
		$(e).addClass('active'); //add active to active nav item
 			
	}

We remove a click event from the navigation links to prevent crazy people trying to break our work. slideIn and slideOut are our product containers. products and slideInProducts are individual product items. tl is our new timeline with a callback function updateNav on start and resetStage on completion.

Now to the fun part of the job.

3. Slides Animation Timeline

	/* Slides Animation */
	function animateSlides(e){
		
		$(navigationLinks).unbind('click');
		
		var pageID = $(e).attr('page'),
			slideIn = $(".ul-slider[page='" + pageID + "']"),
			slideOut = $('.ul-slider.active'),
			products = $($(slideOut).find('li').get()),
			slideInProducts = $($(slideIn).find('li').get()),
			tl = new TimelineMax({onStart:updateNav, onStartParams: [pageID], onStartScope: e, onComplete:resetStage, onCompleteScope: e});
		
		$(slideIn).show();
		$(navigationLinks).removeClass('active');
		$(e).addClass('active'); //add active to active nav item

		tl
		.staggerTo(products, 0.6, {css:{x:'-=960'}, ease:Power4.easeOut }, 0.02)		
		.staggerFromTo(slideInProducts, 0.5, {css:{x:'960'}, ease:Power4.easeIn }, {css:{x:'30'}, ease:Power4.easeIn }, 0.05)
		.staggerTo(slideInProducts, 0.5, {css:{x:'0'}, ease:Elastic.easeOut.config(2) }, 0.05, "-=0.25");
 			
	}

Firstly we animate the current products out of the view x:'-=960', then we animate individual products of the next slide to x:'30'. This is intentional, because we do not want the elastic effect to be calculated from the whole distance of the animation.

The last staggerTo with Elastic.easeOut creates a little elastic bounce at the end of the timeline, which is exactly what we wanted.

"-=0.25" on the last slideInProducts tween makes it overlap with the previous tween and gives the impression of one seamless animation.

4. Slides Reverse Animation Timeline

	/* Slides Animation */
	function animateSlides(e){
		
		$(navigationLinks).unbind('click');
		
		var pageID = $(e).attr('page'),
			pageIDactive = navigationLinks.filter('.active').attr('page'),
			slideIn = $(".ul-slider[page='" + pageID + "']"),
			slideOut = $('.ul-slider.active'),
			products = $($(slideOut).find('li').get()),
			slideInProducts = $($(slideIn).find('li').get()),
			tl = new TimelineMax({onStart:updateNav, onStartParams: [pageID], onStartScope: e, onComplete:resetStage, onCompleteScope: e});
		
		$(slideIn).show();
		$(navigationLinks).removeClass('active');
		$(e).addClass('active'); //add active to active nav item
 		
		if(pageID > pageIDactive){
			
			tl
				.staggerTo(products, 0.6, {css:{x:'-=960'}, ease:Power4.easeOut }, 0.02)
				.staggerFromTo(slideInProducts, 0.5, {css:{x:'960'}, ease:Power4.easeIn }, {css:{x:'30'}, ease:Power4.easeIn }, 0.05)
				.staggerTo(slideInProducts, 0.5, {css:{x:'0'}, ease:Elastic.easeOut.config(2) }, 0.05, "-=0.25");
			
 		} else {
 		
 			var products = $($(slideOut).find('li').get().reverse()),
				slideInProducts = $($(slideIn).find('li').get().reverse());
			tl
			.staggerTo(products, 0.6, {css:{x:'960'}, ease:Power4.easeOut }, 0.02)
			.staggerFromTo(slideInProducts, 0.5, {css:{x:'-=960'}, ease:Power4.easeIn }, {css:{x:'30'}, ease:Power4.easeIn }, 0.05)
			.staggerTo(slideInProducts, 0.5, {css:{x:'0'}, ease:Elastic.easeOut.config(2) }, 0.05, "-=0.25");  
			
		}
		
	}

Now we need to reverse the animation based on the current and next slide position. To do that we compare pageID and pageIDactive, then we reverse the order of the selected products using .reverse(). Finally reverse the x:'-=960' in the reversed timeline.

Conclusion

That’s it! Now we have a nice, smooth bouncy animation as seen on the Apple Store recreated using jQuery and Greensock.

I will explain the remaining functions in the next post and also share the final files with you. Enjoy your day and feel free to leave a comment if you have any questions or feedback.

View Demo View Part Two

Related Aticles

One thought on “Tutorial: Create The Apple Mac Website Navigation Using Greensock [Part 1]

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.