Awesome Cufonized Fly-out Menu with jQuery and CSS3

In today’s tutorial we will create a full page cufonized menu that has two nice features: when hovering over the menu items we will move a hover-state item that adapts […]

From our sponsor: Try Mailchimp today.

In today’s tutorial we will create a full page cufonized menu that has two nice features: when hovering over the menu items we will move a hover-state item that adapts to the width of the current item, and we will slide out a description bar from the left side of the page, reaching towards the current menu item.

We will use jQuery for the effect and some CSS3 properties for the style. We are not going to use any images.

So, let’s start!

The Markup

The HTML structure will consist of an unordered list that represents our menu and a div for the description elements:

<div id="slidingMenuDesc" class="slidingMenuDesc">
	<div><span>Description for "About"</span></div>
	...
</div>

<ul id="slidingMenu" class="slidingMenu">
	<li><a href="#">Home</a></li>
	<li><a href="#">About</a></li>
	<li><a href="#">Portfolio</a></li>
	<li><a href="#">Work</a></li>
	<li><a href="#">Contact</a></li>
	<li><a href="#">Get a quote</a></li>
</ul>

We leave out the description for “Home” since there is nothing to describe. The sliding divs should just appear when we hover over the other items.

The CSS

First, we will style the menu and its navigation items and then we will style the description elements.
Let’s reset some styles:

body, ul, li, h1, h2, span{
	margin:0;
	padding:0;
}
ul{
	list-style:none;
}

The background is going to be dark gray:

body{
	background:#292929;
}

The list for the menu items is going to be positioned absolutely at the right side of the screen:

.slidingMenu {
	position: absolute;
	height:410px;
	width: 410px;
	top:40px;
	overflow:hidden;
	right:1px;
	font-family: Arial, Helvetica, sans-serif;
}

The menu items are hoing to float right:

.slidingMenu li {
	display:block;
	float:right;
	clear:both;
	position:relative;
	overflow:hidden;
}

The “mover” element will be positioned absolutely and we will give it a top and a width dynamically:

.slidingMenu li.move {
	width: 9px;
	height: 68px;
	right:0px;
	padding-right:10px;
	margin-top:2px;
	z-index: 8;
	position: absolute;
	background: #2183c4;
	background:
		-webkit-gradient(
			linear,
			left top,
			left bottom,
			from(#0771b8),
			to(#2183c4)
		);
	background:
		-moz-linear-gradient(
			top,
			#0771b8,
			#2183c4
		);
	-moz-border-radius: 8px 0px 0px 8px;
	-webkit-border-top-left-radius: 8px;
	-webkit-border-bottom-left-radius: 8px;
	border-top-left-radius: 8px;
	border-bottom-left-radius: 8px;
	-moz-box-shadow:1px 1px 5px #000;
	-webkit-box-shadow:1px 1px 5px #000;
	box-shadow:1px 1px 5px #000;
	}

We will give this moving hover element a very subtle background gradient and some box shadow.
The style for the link element will be as follows:

.slidingMenu li a {
	font-size:66px;
	text-transform:uppercase;
	text-decoration: none;
	color: #ddd;
	outline: none;
	text-indent:5px;
	z-index: 10;
	display: block;
	float: right;
	height: 66px;
	line-height: 66px;
	position: relative;
	overflow: hidden;
	padding-right:10px;
}

The descriptions will be in a relatively positioned container. We set the margin-top to the same value like the top of the menu list:

/* Descriptions */
.slidingMenuDesc{
	margin-top:40px;
	position:relative;
}

The div with the description span inside is going to have the same background-gradient like the mover and the same box shadow. The rounded borders are going to be on the opposite corners:

.slidingMenuDesc div{
	background: #2183c4;
	background:
		-webkit-gradient(
			linear,
			left top,
			left bottom,
			from(#0771b8),
			to(#2183c4)
		);
	background:
		-moz-linear-gradient(
			top,
			#0771b8,
			#2183c4
		);
	height: 68px;
	padding-right:5px;
	left:-5px;
	width:0px;
	margin-top:2px;
	overflow:hidden;
	position:absolute;
	-moz-box-shadow:1px 1px 5px #000;
	-webkit-box-shadow:1px 1px 5px #000;
	box-shadow:1px 1px 5px #000;
	-moz-border-radius: 0px 8px 8px 0px;
	-webkit-border-top-right-radius: 8px;
	-webkit-border-bottom-right-radius: 8px;
	border-top-right-radius: 8px;
	border-bottom-right-radius: 8px;
}

We need to set these element absolute, since we will adjust the top to the according current list element that we are hovering.

The description span is going to be positioned absolutely as well. This is not required but it gives you more options if you would like to apply other animation effects:

.slidingMenuDesc div span {
	font-size:36px;
	color: #f0f0f0;
	text-indent:5px;
	z-index: 10;
	display: block;
	height: 66px;
	line-height: 66px;
	position:absolute;
	right:10px;
	margin-left:5px;
	top:-3px;
}

And now, let’s take a look at the JavaScript!

The JavaScript

First, we will add the following scripts to our HTML head:

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"></script>
<script src="cufon-yui.js" type="text/javascript"></script>
<script src="BabelSans_500.font.js" type="text/javascript"></script>
<script src="jquery.easing.1.3.js" type="text/javascript"></script>

And we will add the following script:

$(function() {
	Cufon.replace('a, span').CSS.ready(function() {
		var $menu 		= $("#slidingMenu");

		/**
		* the first item in the menu,
		* which is selected by default
		*/
		var $selected	= $menu.find('li:first');

		/**
		* this is the absolute element,
		* that is going to move across the menu items
		* It has the width of the selected item
		* and the top is the distance from the item to the top
		*/
		var $moving		= $('<li />',{
			className	: 'move',
			top			: $selected[0].offsetTop + 'px',
			width		: $selected[0].offsetWidth + 'px'
		});

		/**
		* each sliding div (descriptions) will have the same top
		* as the corresponding item in the menu
		*/
		$('#slidingMenuDesc > div').each(function(i){
			var $this = $(this);
			$this.css('top',$menu.find('li:nth-child('+parseInt(i+2)+')')[0].offsetTop + 'px');
		});

		/**
		* append the absolute div to the menu;
		* when we mouse out from the menu
		* the absolute div moves to the top (like initially);
		* when hovering the items of the menu, we move it to its position
		*/
		$menu.bind('mouseleave',function(){
				moveTo($selected,400);
			  })
			 .append($moving)
			 .find('li')
			 .not('.move')
			 .bind('mouseenter',function(){
				var $this = $(this);
				var offsetLeft = $this.offset().left - 20;
				//slide in the description
				$('#slidingMenuDesc > div:nth-child('+ parseInt($this.index()) +')').stop(true).animate({'width':offsetLeft+'px'},400, 'easeOutExpo');
				//move the absolute div to this item
				moveTo($this,400);
			  })
			  .bind('mouseleave',function(){
				var $this = $(this);
				var offsetLeft = $this.offset().left - 20;
				//slide out the description
				$('#slidingMenuDesc > div:nth-child('+ parseInt($this.index()) +')').stop(true).animate({'width':'0px'},400, 'easeOutExpo');
			  });;

		/**
		* moves the absolute div,
		* with a certain speed,
		* to the position of $elem
		*/
		function moveTo($elem,speed){
			$moving.stop(true).animate({
				top		: $elem[0].offsetTop + 'px',
				width	: $elem[0].offsetWidth + 'px'
			}, speed, 'easeOutExpo');
		}
	}) ;
});

After we cufonize the font (all “a” elements and all “span” elements), the main function gets executed. We select the first item by default which is our “Home”. When we hover over a menu item we will move the li.move to the right position and slide out the according description item.

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

Tagged with:

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

Feedback 115

Comments are closed.
  1. que buen menu.. exelente trabajo, con su permiso lo utilizare para mi futuros proyectos…
    =)

    • @Jireck That’s a nice idea, do you mean a repeated background or something like a big photo? Cheers, ML

  2. Amazing as usual, even more if you look at the demo with a 1920×1200 px monitor 😉

  3. Another great looking script. Indeed it would look great with a large image on the background. Thanks again for sharing 🙂

  4. Is there any possibilities to add .current class i mean the active page status Mary Lou.

  5. This is not compatible with IE7 atleast. we can ignore IE6 but can’t ignore the IE7 and IE8 and IE9.

  6. Hello Fem, it works fine in IE8 (of course, without the rounded borders since that is CSS3). Actually we should ignore every version except the latest one, which is IE8. Cheers, ML

  7. Is it possible that if you can make it compatible with IE7 as well, I can pay you for doing so. As my client likes it very much and he want to use this menu.

  8. Hi there! Many thanks for the tutorial. Amazing as usual.
    Help needed: I would like to use accentuated letters.
    Many thanks, indeed.

    • Hi! I think, when you created your font here you need to check as well the box for “Latin-1 Supplement” for accented characters. I hope it helps! Cheers, ML

  9. Oh, many thanks. You’re so great. What a quick support! Problem solved.
    🙂

  10. Strongly disagree that support for ie7 should be dropped. According to W3, IE7 has a 9.1% and IE6 has a 7.1% marketshare. It seems odd to me that you would compromise navigation for 16% of users (to be fair, I don’t know that many people browsing your site would use ie6/ie7).

  11. what is so “awesome” about that? i don’t get it. just the fact that you can make it with a certain mix of technologies doesn’t make an old (most time lame) idea awesome. sorry folks. 🙂

  12. A very thorough tutorial, but then let down at the very end. Did you run out of time to explain that final step?
    It got me that far though – I’ll do some trial-and-error with the cufon stuff to finish off on my own.
    Thanks.
    Martin

  13. I cannot get this to work 🙁
    I have the nav menu, but none of the blue animation or bars appear. All I have is the grey background and the the nav words 🙁
    Any suggestions? Martin

  14. Has anyone created a working version compatible with IE7? If so, I’d love to see a demo… Thanks!

  15. I am attempting to use this piece as a part of my project. I can’t for the life of me get a background image to load via css or html. Help? I’ve also been trying to constrain the whole thing within another <div that is sized specifically w1152xh1200. Is this possible?

  16. Great menu, very compliments!
    But can someone explain me why you have to use
    ‘li:nth-child(‘+parseInt(i+2)+’)’
    and not
    ‘li:nth-child(‘parseint(i+2)’)’
    when declaring ‘top’ in the slidingMenuDesc?
    and why i+2 and not i?
    Thank you very much!

  17. Well, what if I want to use this for page sessions, how can I make it so that if I want “portfolio” to be the main selected menu, and then change if I go back to home, and so forth with the rest of the sessions.
    Any ideas?

  18. i love the effect and i would live to know how i can make th emenu onclick always open that i can include more information , links and images inside the , any idea

    thanks

  19. QUISIERA USAR ESTE MENU PERO DOBLE EN ALGUNA PAGINA PERO HE INTENTADO HACER EL EFECTO AL CONTRARIO PERO NO LOGRO HACER QUE LA PARTE QUE SE MUEVE ENCAJE PERFECTAMENTE .. ES DECIR LOGRO HACER QUE LA ANIMACION SALGA DE DEREECHA A IZQUIERDA PERO NO LOGRO HACER QUE LLEGUE JUSTO A DONDE TERMINA CADA PALABRA COMO LO HACE EL CODIGO ORIGINAL …. ME GUSTARIA QUE ME PUDIERAN DECIR QUE VARIABLE CAMBIO EN EL CODIGO JAVASCRIPT PARA HACER QUE ESTA ANIMACION FUNCIONE HACIA EL OTRO LADO

  20. @ML, you’re like a designers magnet! This concept rocks, as per usual for you 🙂
    Btw I used a background slider with the browser constrained to 1024×768 and this menu of yours works like a charm.

    I am having difficulty contraining the menu within a ‘main’ div where the page content is centered. I manage to lock down the description (left) of the menu, but not the right. I’ll keep on trying, but if you have an idea of how to lock it down to a div instead of the browser, that would be great. Not sure it is designed to do that though.

  21. Ok, managed to get this menu working in a div width. I am just experiencing one weird effect and that is the description div flying out too far and overlapping the menu div that then caused the option to be obscured and a lot of jitter.
    Anyone have any ideas as to how the fly-in can be controlled in terms of the amount the description div is expanding across the width of the page / div? I do not find any option in either the CSS or JS to change this…

  22. Clarification – when I run the above inside a div (I use it with a slider as a background – ML, that looks great btw) and when viewed in a 1024 x 768 sized browser, looks perfect.

    When I expand it to my own maximum, iow beyond a standard resolution, the description span flies out much further and ends up obscuring the menu div and that causes jitter, all during the mouse over event. Is the length (width) of the span tied to the screen through the js or is there some CSS I need to amend that I am missing?

  23. Dude.. This is amazing.. I really loved it, and thanx for sharing the most significant style with CSS3.. I’ve tried many places before but this one is awesome..

    Thanx Dude!!!!!
    Really Loved it!!
    You are CSS ROCKSTAR!!!!!!

  24. Hey thanks for this, I am so excited to put it to use. I was wondering if there is a way to have the nav be persistent, so that when the page scrolls down, the nav follows?

    Thanks,
    Kris

  25. First of all, Mary Lou, this is an absolutely fantastic tutorial. I’m working on redesigning our website with a menu based on this, but I was just wondering how you would go about switching the sides so that the menu items appear on the left and the slide out text comes from the right.

  26. Thank you for this! I am having problems though implementing this in WordPress. Do I just upload the .zip file into the site?

  27. What should I change in code lines to get opposite effect? List for the menu items is going to be positioned absolutely at the right side of the screen. I want menu positions at the left side of screen and divs with the description span inside move to the right. Simply say: I need mirror reflection of this effect. Is this possible? Can you show me how to do this? Please 🙂

  28. Love the script, but I’m wondering if you can help with a problem!

    Basically, as soon as I insert a separate slideshow gallery, this menu stops working.

    This is what I’m inserting:

  29. How can I get it to stay hovering on the current page, instead of returning to the top of the list?

  30. * the first item in the menu,
    * which is selected by default
    var $selected = $menu.find(‘li:first’);

    Can anyone tell me how select a different menu item by default?

  31. I can get it to eventually hover on the selected page by changing this:

    var $selected = $menu.find(‘li:first’);

    to this:

    var $selected = $menu.find(‘#thispage’);

    and putting id=”thispage” on the li for the page like

    Services

    However, it only works once I’ve moused over the menu. When it first loads, it’s still hovering over the first element. I’m still digging to try to find where the draw is initialized on page load.

  32. Great! I’ve tried to change the active status, but it doesn’t work. How can I do?

    .slidingMenu li a:active {
    text-transform:lowercase;
    }

  33. Alright, I’ve got it holding an active status appropriately. The necessary changes are listed below.

    This part will tell the script which menu item to make active. For the example menu, if you wanted to make “Portfolio” the active item, you would have to add an id = “thispage” to the list item like this:

    “09 Portfolio

    This script change makes the script recognize the item which has been made active, instead of just keeping the first item active.
    In the script, change:
    “05 /**
    06 * the first item in the menu,
    07 * which is selected by default
    08 */
    09 var $selected = $menu.find(‘li:first’);”

    to this:
    “05 /* select menu item with id = “thispage” */
    06 var $selected = $menu.find(‘#thispage’);”

    This next part is kind of odd. Setting the top position for the selected element wasn’t working in the code. A good bit of debugging never made it obvious why the original placement for the code didn’t work.
    In the script, change this:
    “/**
    12 * this is the absolute element,
    13 * that is going to move across the menu items
    14 * It has the width of the selected item
    15 * and the top is the distance from the item to the top
    16 */
    17 var $moving = $(”,{
    18 className : ‘move’,
    19 top : $selected[0].offsetTop + ‘px’,
    20 width : $selected[0].offsetWidth + ‘px’
    21 });”

    to this:
    ” /**
    12 * this is the absolute element,
    13 * that is going to move across the menu items
    14 * It has the width of the selected item
    15 * and the top is the distance from the item to the top
    16 */
    17 var $moving = $(”,{
    18 className : ‘move’,
    19 top : $selected[0].offsetTop + ‘px’, /* <– this doesn't work */
    20 width : $selected[0].offsetWidth + 'px'
    21 });
    22
    23 $moving.css('top',$selected[0].offsetTop + 'px'); /* <– this fixes the problem */"

    Hopefully I've caught all of the changes and the formatting of the comment section keeps the code changes mostly intact.

  34. Ahh, forgot about the html being accepted in comments. The Portfolio item with the id should look like this

    “09 [li id = “thispage”][a href=”#”]Portfolio[/a][/li]”

    with the square brackets swapped out for the > & < as appropriate in html.

  35. Brian: in .slidingMenu
    change changing the position to relative… and maybe top:0px etc to fit the div…

    thanks Mary for the tutorial 🙂