Collapsing Site Navigation with jQuery

Today we will create a collapsing menu that contains vertical navigation bars and a slide out content area. When hovering over a menu item, an image slides down from the […]

Today we will create a collapsing menu that contains vertical navigation bars and a slide out content area. When hovering over a menu item, an image slides down from the top and a submenu slides up from the bottom. Clicking on one of the submenu items will make the whole menu collapse like a card deck and the respective content area will slide out.

The beautiful fashion photos are taken from Beyrouth’s photostream on flickr. The specific set can be found here.

So, let’s get started!

The Markup

Our HTML will consist of a main container with the class and id “cc_menu”. Here we will place all our vertical menu items and the main content div:

<div id="cc_menu" class="cc_menu">
	<div class="cc_item" style="z-index:5;">
		<img src="images/1.jpg" alt="image" />
		<span class="cc_title">Collection</span>
		<div class="cc_submenu">
			<ul>
				<li class="cc_content_1">Winter 2010</li>
				<li class="cc_content_2">Spring 2011</li>
			</ul>
		</div>
	</div>
	<div class="cc_item" style="z-index:4;">
		<img src="images/2.jpg" alt="image" />
		<span class="cc_title">Stores</span>
		<div class="cc_submenu">
			<ul>
				<li class="cc_content_3">Milano</li>
				<li class="cc_content_4">Paris</li>
			</ul>
		</div>
	</div>
	...
	<div id="cc_content" class="cc_content">
		<span id="cc_back" class="cc_back"><< Go back</span>
		<div class="cc_content_1">
			<h1>Winter 2010</h1>
			<p>Some content</p>
		</div>
		<div class="cc_content_2">
			<h1>Spring 2011</h1>
			<p>Some content</p>
		</div>
		...
	</div>
</div>

The first item will get a z-index of 5 and then we will decrease the z-index for the next items. This will make the last item be in the lowest layer. We do this in order to create the card deck collapsing effect.

Each submenu item will share its class with the respective content div. Like that we can make the right content div appear whenever we click on a submenu item.

Let’s take a look at the styling.

The CSS

Our main div that surrounds everything will have the following style:

.cc_menu{
	width:700px; /*140px * 5*/
	height:600px;
	position:relative;
	font-size:14px;
	text-transform:uppercase;
	color:#fff;
}

The width of this container is the sum of all the item widths which is 5 times 140 pixels.

The style of each navigation item will be the following:

.cc_item{
	text-align:center;
	width:140px;
	height:600px;
	float:left;
	border-bottom:1px solid #000;
	background:#444 url(../images/bg.png) repeat top left;
	position:relative;
	-moz-box-shadow:3px -3px 10px #000;
	-webkit-box-shadow:3px -3px 10px #000;
	box-shadow:3px -3px 10px #000;
}

We will give each item a box shadow so that the layering becomes visible. (That does not work in IE yet, so you will have to add a border or some other background image that enhances this.)

The title in each menu element will have a dark background with a subtle shadow around:

span.cc_title{
	color:#fff;
	font-size:16px;
	top:200px;
	left:5px;
	position:absolute;
	padding:3px 0px;
	background:#111;
	width:130px;
	display:block;
	z-index:11;
	-moz-box-shadow:1px 1px 4px #000;
	-webkit-box-shadow:1px 1px 4px #000;
	box-shadow:1px 1px 4px #000;
}

The submenu list will be styled as follows:

.cc_submenu ul{
	list-style:none;
	width:140px;
	margin:0;
	padding:0;
	height:0px; /*increase to 200px to slide up*/
	overflow:hidden;
	text-align:left;
	background:#000;
	position:absolute;
	left:0px;
	bottom:0px;
	opacity:0.7;
	z-index:13;
}

We will position the list at the bottom of the item and give it a height of 0 pixel. We will then increase the height to 200 pixels for it to slide up from the bottom.

The list elements of the submenu list will have the following style:

.cc_submenu ul li{
	color:#ddd;
	cursor:pointer;
	padding:10px;
}

The image that will slide in from the top will be positioned negatively, meaning that we will hide it at the top of the item and the page:

.cc_item img{
	position:absolute;
	width:140px;
	height:600px;
	top:-600px;
	left:0px;
}

In our JavaScript function we will make it slide down from the top by animating the top value to 0px.

The div that surrounds all the contents will also be hidden to the left of the page by setting the left value to -700 pixels:

.cc_content{
	width:600px;
	height:600px;
	border-bottom:1px solid #000;
	position:absolute;
	left:-700px;
	background:#444 url(../images/bg.png) repeat top left;
	overflow:hidden;
	-moz-box-shadow:4px 0 7px #000;
	-webkit-box-shadow:4px 0 7px #000;
	box-shadow:4px 0 7px #000;
}

The single content divs will have the following style:

.cc_content div{
	display:none;
	margin:20px;
}

We will give each paragraph the following style:

.cc_content p{
	background:#000;
	padding:20px;
	opacity:0.7;
}

And finally, we will position the back span at the bottom right of the content container:

span.cc_back{
	position:absolute;
	bottom:10px;
	right:10px;
	cursor:pointer;
	color:#ddd;
}

And that was the style. Now, let’s take a look at the JavaScript magic.

The JavaScript

We will have several function taking care of the behavior of our navigation. Whenever we hover a menu item, we want the image to slide in from the top and the submenu to slide in from the bottom. And, of course, when we leave an item, we want the reverse to happen. The functions m_enter and m_leave take care of that behavior.
The function fold will make the menu collapse once a submenu item is clicked. The initial position is recovered by the function unfold.
The two functions showContent and hideContent take care of the respective content appearing and disappearing.

In our main jQuery function we will start by defining some variables:

//all the menu items
var $items 		= $('#cc_menu .cc_item');
//number of menu items
var cnt_items	= $items.length;
//if menu is expanded then folded is true
var folded		= false;
//timeout to trigger the mouseenter event on the menu items
var menu_time;

Now we will bind the mouseenter and the mouseleave to each item. We will also bind the click event to list elements in the submenu:

$items.unbind('mouseenter')
	  .bind('mouseenter',m_enter)
	  .unbind('mouseleave')
	  .bind('mouseleave',m_leave)
	  .find('.cc_submenu > ul > li')
	  .bind('click',function(){
	var $li_e = $(this);
		  //if the menu is already folded,
		  //just replace the content
	if(folded){
		hideContent();
		showContent($li_e.attr('class'));
	}
		  else //fold and show the content
		fold($li_e);
});

In the following we will define the m_enter function:

function m_enter(){
	var $this 	= $(this);
	clearTimeout(menu_time);
	menu_time 	= setTimeout(function(){
	//img
	$this.find('img').stop().animate({'top':'0px'},400);
	//cc_submenu ul
	$this.find('.cc_submenu > ul').stop().animate({'height':'200px'},400);
	},200);
}

The timeout is used to prevent this event to trigger if the user moves the mouse with a considerable speed through the menu items.

The m_leave function is defined as follows:

function m_leave(){
	var $this = $(this);
	clearTimeout(menu_time);
	//img
	$this.find('img').stop().animate({'top':'-600px'},400);
	//cc_submenu ul
	$this.find('.cc_submenu > ul').stop().animate({'height':'0px'},400);
}

When clicking on the back span, we want the unfold function to trigger:

$('#cc_back').bind('click',unfold);

The fold function will show only the menu column of the chosen submenu and make all the other items animate to the left by setting the margin to -140 pixels:

function fold($li_e){
	var $item		= $li_e.closest('.cc_item');

	var d = 100;
	var step = 0;
	$items.unbind('mouseenter mouseleave');
	$items.not($item).each(function(){
		var $item = $(this);
		$item.stop().animate({
			'marginLeft':'-140px'
		},d += 200,function(){
			++step;
			if(step == cnt_items-1){
				folded = true;
				showContent($li_e.attr('class'));
			}
		});
	});
}

The unfold function shows all the menu items and also hides any item’s image and submenu that might be displayed:

function unfold(){
	$('#cc_content').stop().animate({'left':'-700px'},600,function(){
		var d = 100;
		var step = 0;
	$items.each(function(){
			var $item = $(this);

			$item.find('img')
				 .stop()
				 .animate({'top':'-600px'},200)
				 .andSelf()
				 .find('.cc_submenu > ul')
				 .stop()
				 .animate({'height':'0px'},200);

			$item.stop().animate({
			'marginLeft':'0px'
			},d += 200,function(){
				++step;
				if(step == cnt_items-1){
					folded = false;
					$items.unbind('mouseenter')
						  .bind('mouseenter',m_enter)
						  .unbind('mouseleave')
						  .bind('mouseleave',m_leave);

					hideContent();
				}
			});
		});
	});
}

The function to show the content will animate our content container to the right by setting the left value to 140 pixels. It will also fade in the respective content:

function showContent(idx){
	$('#cc_content').stop().animate({'left':'140px'},200,function(){
		$(this).find('.'+idx).fadeIn();
	});
}

And finally, the function to hide the content:

function hideContent(){
	$('#cc_content').find('div').hide();
}

To cufonize the font in our menu, we will simply add these lines to the head of our HTML:

<script src="js/cufon-yui.js" type="text/javascript"></script>
<script src="js/Liberation_Sans.font.js" type="text/javascript"></script>
<script type="text/javascript">
	Cufon.replace('span');
	Cufon.replace('li');
	Cufon.replace('h1');
	Cufon.replace('p');
</script>

We will be using the font Liberation Sans which you can also find here.

And that’s all! We hope you enjoyed this tutorial and find it useful!

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

Feedback 124

Comments are closed.
  1. Please, I want to put a lightbox gallery in the div content, but it doesn’t work. What I have to do?

  2. Hi, thanks a lot. I like that.
    But I have a question like JOS wrote above – how I can change content in div (#content) from other pages. I’m not strong in js and all my attempts are fall. I’ll appreciate you if let advice. Thanks

  3. //function to show the content
    function showContent(idx){ $(‘#cc_content’).stop().animate({‘left’:’140px’},1000,function(){
    $(this).find(‘.’+idx).fadeIn();
    // $(this).find(‘.’+idx).jScrollPane();
    // return false;
    });
    }
    I had added the two lines that nor are comments, tryng to get this work with jscrollpane.
    of course it didn´t work.
    Can you help, please? May be it will result intresting for many oeaple just learning and you design will be more usefull.

    sorry for disturbin, my ignorance and my bad english.
    Cheers for your work, mary!

  4. i’m somewhat new to jquery and am having a problem adding a contact form into the one of the cc.content
    class divs and am noticing that it doesn’t seem to be possible to add any divs to any of the cc.content
    class divs at all.

    how do i get around this and/or what am i doing wrong?

    thanks for any help!

  5. Very nicely done. Have a problem with German umlauts like ö, ä, ü. These are not displayed. has anyone a tip

  6. n1ce …!

    i have a big question about this….

    I would like to hide the “button” if i take the mouse over the “menu”. And i would like to “make link” all of the picture….how to change the javascript to reach this …?! …Can u help me ?!

    Sorry 4 my bad english 🙁

  7. Hi.. I am wondering if you may be able to advise how I could get the cc_item background to change every refresh.. I have tried messing with some javascript below but dont know what div ids to assign and also if I need to change anything in the Css file.

    }
    –>

    Trying to rotate the background of the nav at every refresh with some textures.

    Any Help would be appreciated.. 🙂 ..

    Thank you.. such a great menu… just want to customise it a bit more..

  8. Really nice!

    I just have one question. How can I get this working together with Ben Almans jquery-bbq-plugin?

    Any hint?

    Thank you!

  9. I would like to change the “Go Back” to be a menu of the top-level links (I.e. “Collection,” “Stores,” “About,” etc.) I’ve been slamming my head against the wall to try and do this, so if anyone has done this successfully, please e-mail me: joe.beaudoin (at) gmail (dot) com. Thank you.

  10. Awesome tutorial!!!. I do this centering and its work but the whole menu is give a position of -700 to make it hidden which would work since it is left aligned but not for a centered menu and the index-5.
    Please help!!!

    take a look please:

    http://www.ilsarrabus.com

  11. how to insert link to specific page of website from an external page i.e. I’m on qwerty.htm page and I want insert a link to the contact page of a site collapsing-site-navigation.htm?
    which parameter I’ve to insert to get the page and not the “homepage”
    please help me!!
    thanks a lot in advance
    cao

  12. ok i found the problem, maybe it is intressting for the autor:

    I changed this in the code:
    function hideContent(){
    $(‘#cc_content’).children(‘div’).hide();
    }

    Greets Daniel

  13. Thanks for great component!

    Question – I have placed a Cyrillic text in titles, menus and content but its not showing…. Any ideas?

    Many thanks!

  14. Hi,

    The tutorial is amazing !. I have problem with the characters like á,é,í,ó,ú. I tried with &aacuote; for example to the á, but it’s not working. I will investigated, but if you have any idea please let me know.

    Thanks

  15. Any ideia how to make the content load of the section after we click instead loading everything when we are in the home.

    Ajax Request?

    Thanks

  16. Hi, i think there is a problem with it in IE9, when i open it and allow the blocked content (ActiveX), the text does not show up. The sliding animation still works and the photos are there but none of the text over the photos appears.

  17. I was trying to put light box inside this menu but I cant get it to show up so I was wondering if anyone had any ideas

  18. Oh yea Im having trouble because if I try putting a div inside of the content container it wont show up and its not just lightbox its any div i put in. Im pretty new to web design so I may just not know what Im doing haha

  19. Any idea how can i put any divs, li´s or other elements inside content without breaking the background?

  20. For those of have problems with putting divs inside the content div just give a style to your div with display:block and it will show up. By default every div inside .content have display:none

  21. Hello Mary Lou: I want to run a contact form from the menu in this form there is a date field that I want to order a calendar, but not working. What can be?
    Thanks – Tato

  22. Hello, indeed lovely navigation. However, I have also found hard to link between tabs like several other readers. Does anybody have idea how to accomplish that. For example, I would like to have link in first tab that links to second one. I would be great if everything is first unfolded 🙂
    Thanks

  23. It is really nice, but there are some issues in IE7 after folding the Item the content is not shown and the page will stuck and return and javascript error. so kindly help …

  24. Can someone help me to change the “cc_item” background to be a different image for each fold away section..

    I’d liked to have a black and white photo in the background and when you hover it, the hovered section shows the colored photo.

    Thanks!!

  25. Love this tutorial!
    I have a question 🙂
    How can i add another sub-menu to div content?
    for example one of my slides is called gallery, and i want to add another menu that will dislpay in cc-content div.
    Is it possible?

  26. I absolutely love your work. I am trying to use this on a site now. How can I make this work with multiple navigations? Meaning having multiple nav boxes. Any help would be GREATLY appreciated. The problem seems to be finding the right selector for #cc-content, but thats as far as I have gotten with it.

  27. Thanks for the tutorial. I wanted to know if there was a way to go to a different section from inside a chosen selection. What i mean is lets say you are inside reading the “Collection” tab and want to have a link so you go straight to your contact page. This is similar to the back button, but instead of just closing the opened section and showing the menu again. I want it to open the contact section instead. Any help would be greatly appreciated

  28. Hi, I’ve got a problem with the script: when I want to add more items (cc_content_9 –> cc_content_10) the script shows the false info (10 reads as 1 ?). How can I add more (cc_content_10 etc) without getting this problem? I used the alfabet instead of numbers, but alas….
    pleas feel free to mail me, thanx!

    Best regards, Mrsinkie

  29. I just try to make some website used this template tonight, it’s hard to make the menu center aligned, it must be change whole script..

    So, I just let those menu stay in left..

    Sorry for my bad english..