Try Tuts+ Premium, Get Cash Back!
How to Build a Lava-Lamp Style Navigation Menu
videos

How to Build a Lava-Lamp Style Navigation Menu

Tutorial Details
  • Technology: HTML, CSS, JavaScript
  • Difficulty: Intermediate
  • Video Length: 35 Minutes

A couple weeks ago, I created a screencast that demonstrated how to build a three-level navigation menu. In a response email, one of our readers requested a tutorial on how to build a lava-lamp style menu. Luckily, it’s quite a simple task, especially when using a JavaScript library. We’ll build one from scratch today.

Screenshot

Prefer a Screencast?

Step 1 Create the Mark-up

Before we can create this neat functionality, we need a base from which to work from. In your favorite code editor, create an unordered list for your navigation, and import both jQuery and jQuery UI, via Google.

<!DOCTYPE html>

<html lang="en">
<head>
	<meta http-equiv="Content-Type" content="text/html; charset=utf-8"> 
	<title>SpasticNav  Plugin</title>
	<link rel="stylesheet" href="css/style.css" type="text/css" media="screen" />
</head>
<body>

<div id="container">

	<ul id="nav">
		<li id="selected"><a href="#">Home</a></li>
		<li><a href="#">About</a></li>
		<li><a href="#">Blog</a></li>
		<li><a href="#">More About My Portfolio</a></li>
		<li><a href="#">Contact</a></li>
	</ul>

</div>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4/jquery.min.js" type="text/javascript"></script>	

<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.7.2/jquery-ui.min.js"></script>
     
</body>
</html>	

Note how we gave an id of “selected” to the home page. This is fairly standard in most websites; it allows use to target the current page, and style that particular list item accordingly.

Next, we must decide how to best implement the lava-lamp functionality. To allow for reusability, we’ll package this little script into a plugin, and call it like:

$('#nav').spasticNav();

Since we’ve decided to build a plugin, let’s go ahead and create a new file for that script, and reference it in our mark-up. We’ll call it jquery.spasticNav.js.

<script type="text/javascript" src="js/jquery.spasticNav.js"></script>	

<script type="text/javascript">
$('#nav').spasticNav();
</script>
</body>

Step 2 Beginning the Plugin

To reduce the number of global variables that we must create, as well as remove any possibilities of the $ symbol clashing with other JavaScript libraries, let’s wrap our plugin in a self-executing anonymous function.

(function($) {
   
})(jQuery);

Now, jQuery will be passed into our plugin, and will be represented via the $ symbol.

Next, it’s generally a best practice to give the users of the plugin as much flexibility as possible. As such, we’ll give them the option of passing in an object-literal when they call the plugin to override a handful of settings. As I see it, they should be able to:

  • Set the amount of overlap for our little blob. This refers to how much the blob will exceed the height of the navigation menu.
  • Set the speed
  • Set a reset, which causes the blob to move back to the current page item (assuming that the user never clicks on a link)
  • Set the color of the blob. This can be accomplished with CSS, but it’s a nice convenience, nonetheless.
  • Set the easing option.

Now, we’ll name our plugin, and make it equal to a function. $.fn is simply an alias for jquery.prototype.

$.fn.spasticNav = function(options) {

};

Knowing that we’ll be allowing these overrides, we must make sure that we accept an “options” parameter.

Step 3 Configuration Options

Now that we’ve named our plugin, the next step is to create the configuration options.

options = $.extend({
	overlap : 20,
	speed : 500,
	reset : 1500,
	color : '#0b2b61',
	easing : 'easeOutExpo'
}, options);    

Above, we’re taking the options variable, setting some default properties and values, and then extending it with whatever (if anything) the user passes in when they call the plugin. That way, the options they pass will override our default settings. For example, if, when I call this plugin, I pass:

$('#nav').spasticNav({
   speed : 2000,
   easing : 'easeOutElastic'  
});

Those two properties will override the default settings, while the remainder of the options will remain the same.

Step 4 Implementing the Functionality

Now, we’re ready to cycle through each element that was passed to this plugin, and implement the lava-lamp functionality. Remember, we can’t assume that the user is going to pass a single element to this plugin. They could, if they wanted, reference a class, which refers to multiple items that should receive this functionality. As such, we’ll call this.each to iterate over each item in the wrapped set.

return this.each(function() {

});

Within this function, we’ll create some variables. Not all of them will immediately have values, but since the JavaScript engine will hoist all variable names to the top of the function anyways (behind the scenes), it’s generally a best practice to declare them at the top, and then initialize them later.

var nav = $(this),
	currentPageItem = $('#selected', nav),
	blob,
	reset;
  • nav : “Caches” this, wrapped in the jQuery object.
  • currentPageItem : Contains the list item with an id of selected. We pass a second parameter to set the context to search from. That way, we don’t have to traverse the entire dom to find this element.
  • blob : For lack of a better word, this variable will reference the highlighter, that will follow our mouse when we hover over the menu.
  • reset : This will store a reference to the setTimeout function that will create later. It’s needed in order to call clearTimeout. More on this soon…

Now that we’ve declared/initialized our variables, let’s create the actual blob, so to speak.

$('<li id="blob"></li>').css({
	width : currentPageItem.outerWidth(),
	height : currentPageItem.outerHeight() + options.overlap,
	left : currentPageItem.position().left,
	top : currentPageItem.position().top - options.overlap / 2,
	backgroundColor : options.color
}).appendTo(this);

The reason why we’re calling the CSS method, rather than simply adding a class, is because these values will vary depending on the current page’s list item. As such, we must use JavaScript to retrieve they values.

  • width: Get the width of currentPageItem, including any borders and padding.
  • height: Get the height of currentPageItem, including any borders and padding. Also, add the amount of overlap, to make the blob extend outside of the menu.
  • left: Sets the left property of the blob equal to the left position of the currentPageItem. (We must set a positioning context in our CSS for this value to take effect.)
  • top: Sets the top value as well, and vertically centers the blob.
  • backgroundColor: Sets the background color.

Finally, we append this new list item to this, or #nav.

Next, we need to store a reference to #blob. That way, we don’t have to search the DOM everytime we wish to access it. We declared the blob variable at the top of the function. Now, let’s initialize it.

blob = $('#blob', nav);

Step 5 The Hover Event

We must now “listen” for when the user hovers over one of the list items (excluding the blob of course) in our navigation menu. When they do, we’ll set the width and left properties of the blob equal to that of the currently hovered list item.

$('li:not(#blob)', nav).hover(function() {
	// mouse over
	clearTimeout(reset);
	blob.animate(
		{
			left : $(this).position().left,
			width : $(this).width()
		},
		{
			duration : options.speed,
			easing : options.easing,
			queue : false
		}
	);
}, function() {
	// mouse out	
	reset = setTimeout(function() {
		blob.animate({
			width : currentPageItem.outerWidth(),
			left : currentPageItem.position().left
		}, options.speed)
	}, options.reset);
	
});

To summarize the script above…

  • Get all list items – not the #blob – within the navigation menu, and when they’re hovered over, run a function.
  • Animate the blob, and set its left and width values equal to that of the hovered list item.
  • Pass an object literal as the second parameter of animate, and set the duration and easing equal to what we set in our configuration options. Set queue to false to prevent animation build-up.
  • When they mouse out, call setTimeOut, which will push the blob back to the current page item. If we didn’t do this, and the user didn’t click on a navigation link, the menu would show that they were on
    a different page entirely. This will, after a second or so, animate the blob back to currentPageItem.

And that’s all there is to it! This is a super simple plugin. The next step is to style our navigation menu.

Step 6 Styling the Menu

Without any styling, our menu should look similar to this:

Unstyled mark-up

Let’s first style the “nav” ul. Open your style.css file, and add:

#nav {
	position: relative;
	background: #292929;
	float: left;
}    
Styling the navigation menu

Next, we’ll style each list item.

#nav li {
	float: left;
	list-style: none;
	border-right: 1px solid #4a4a4a;
	border-left: 1px solid black;
}    

This simply floats each list item to the left, and adds a border to each side.

Styling the list items

Moving along, we next must style the anchor tags within our navigation menu.

#nav li a {
	color: #e3e3e3;
	position: relative;
	z-index: 2;
	float: left;
	font-size: 30px;
	font-family: helvetica, arial, sans-serif;
	text-decoration: none;
	padding: 30px 45px;
}    

We’re setting a color, floating them to the left, setting some font values, and a healthy amount of padding. Take note of the z-index property. This is a necessity, and will be explained shortly. However, remember that, in order to adjust the z-index, we must set a positioning context, which we’ve done.

Styling the anchor tags

Because we’re not implementing a full reset stylesheet, let’s ensure that we zero out any default margins and padding on our ul and li, just to save any potential headaches.

ul, li {
	margin: 0; padding: 0;
}    

The last step is to style the blob itself!

#blob {
	border-right: 1px solid #0059ec;
	border-left: 1px solid #0059ec;
	position: absolute;
	top: 0;
	z-index : 1;
	background: #0b2b61;
	background: -moz-linear-gradient(top, #0b2b61, #1153c0);
	background: -webkit-gradient(linear, left top, left bottom, from(#0b2b61), to(#1153c0));
	-moz-border-radius: 4px;
	-webkit-border-radius: 4px;
	-moz-box-shadow: 2px 3px 10px #011331;
	-webkit-box-shadow: 2px 3px 10px #011331;
}    

Once again, we set some pretty colors for our borders, and add some background colors (including CSS3 gradients/borders/shadows for Firefox and Safari/Chrome). Once again, we see that z-index property. Without this, the blob will display above all of the text in the navigation menu. To counter this, we must be sure that its z-index property is LOWER than the list item’s! We also must set the position to absolute in order to adjust its top and left values with our plugin.

Screenshot

Conclusion

That’s all there is to it! With minimal effort, we’ve created a really neat looking navigation menu from scratch. Let me know if you have any questions! Thanks for reading and watching.

Note: Want to add some source code? Type <pre><code> before it and </code></pre> after it. Find out more
  • http://twitter.com/kr3wsk8a Cody Robertson

    Awesome, I saw your demo of this like a week ago or so on twitter and liked it enough to try and replicate it myself. I did it a bit different (no plugin) but still a great effect!

    Seems like you worked out the bugs too!

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      Oh really? I’d love to see it. :)

      • http://www.ashisoft.com Ashi

        I loved too!

  • http://www.milosmilikic.com Milos Milikic

    Thanks for this tutorial! I will look it later! Cheers!

  • http://www.rickymills.com Rick

    Its a nice menu….but doesnt even come close to resembling anything remotely lava-lamp related… :s

    Whys it being called a lava-lamp style menu?

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      I generally associate that term with this kind of menu, where a highlighter follows your mouse from list item to list item.

      • http://ramblingwood.com Alec Gorge

        I think he means that he doesn’t get the term in general. Why is any menu of this style called a lava lamp menu? It looks nothing like a lava lamp!

      • http://www.jeffrey-way.com Jeffrey Way
        Author

        Oh – haha. Yeah, it’s a bit strange.

    • http://www.cbesslabs.com Sebastian Bratu

      I believe it’s supposed to imitate the flow of the lava inside a lava lamp when you move it, or when it moves inside the cylinder.

    • Caoimh

      I think the first of this kind of menu looked a little more ‘lava lampish’ as in the highlight wobbled and looked a bit more like a blob of hot wax!….here’s one that looks a little more blobby: http://www.gmarwaha.com/blog/2007/08/23/lavalamp-for-jquery-lovers/

  • http://www.foxyturkey.com Yigit Ozdamar

    Nice tut Jeffrey! But i think it will be better if you will remove the out-lines from the demo page. It looks ugly when you click the nav. ;)

    Thanks

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      Yeah – you’re right. I’ll update the demo when I get home.

      To others, if you don’t like the outline when you click, just set outline: 0; in your CSS file under the #nav li a section.

  • # Fez J

    Awesome tutorial!

    Just got done watching, thanks! :D

  • khaled

    nice tut keep it up, i love it! thank you jeffrey

  • http://butenas.com Neoman

    This is really nice tut! Will use this in the future project, I think :)

  • Michele

    How does this look like a lava lamp?

    • http://tutorial-city Tutorial City

      Lavalamp is a kinda MENU where the Highlighter follows the menu navigation :)

  • http://www.canaydogan.net Can Aydoğan

    Nice tut. Thanks…

  • http://www.art2code.com Art2code

    i love it
    Awesome tut !
    thx

  • http://freka.net fredrik

    Wouldn’t it be better to use a class for “selected” rather than an id? If you have other elements on the page where it would be useful to use “selected”, using the id attribute on them all would cause validation to fail.

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      Yeah, perhaps. :)

  • http://www.twitter.com/addiiis Diogo

    Thanks for this tutorial!

  • http://webexpedition18.com Nikola

    Great tutorial, I will try it for sure!

    Thanks :)

  • http://www.complimedia.com Montana Flynn

    Opera 10 recognizes box-shadow and border-radius, so it’s nice to use them ;)

  • http://tutorial-city Tutorial City

    Opera 10 recognizes box-shadow and border-radius, so it’s nice to use them ;)

    PS:The message from Montana Flynn was posted by me, but I have no idea how this cookie was inserted on my browser! I apologize and ask the admin to delete this entry. Thanks

    • Sosby

      Chrome 5 (dev) does also.

  • Sulaiman

    Would it be possible to make it so that the “blob” changes colors for each item? Like hovering over “Home” would make it red, then moving to “About” would change it to orange, etc.

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      Definitely. You could attach a data() value to each list item in your navigation menu. And then, when you hover over an item, you grab that value, and set it as the blob’s background color. I’ll try to write a quick demo when I have the chance.

      • http://www.jeffrey-way.com Jeffrey Way
        Author

        This is 60 second crude example…but it gets the idea across.

        http://jsbin.com/ezuli

    • http://www.itpixels.com itpixels

      Here’s a working demo of the effects that you want to achieve.

      http://css-tricks.com/examples/MagicLine/

  • Roland

    For those curious about the name Lava-Lamp (LavaLamp) – http://www.gmarwaha.com/blog/2007/08/23/lavalamp-for-jquery-lovers/

    LavaLamp was a jQuery implementation inspired by a MooTools implementation called Fancy Menu – later renamed MorphList
    CSS+JS Power. Fancy Menu : http://devthought.com/blog/projects-news/2007/01/cssjavascript-true-power-fancy-menu/
    MorphList : http://devthought.com/projects/mootools/morphlist/

  • http://www.firedartonline.com/ FireDart

    Nice tutorial, I have seen tons of examples of what you just created but yours is by far the best, you also do a great job on explain how you made it which is good for a jQuery beginner like my self ;)

    Thanks Jeffrey!

  • http://www.ahmasud.com Masud

    Awesome tutorial, Thanks a lot

  • http://www.elmorron.com.ar taquito

    It’s nice, but i prefer this one

  • http://www.xcellence-it.com/ Xcellence IT

    Awesome effects… with simplicity…

    Thanks

  • http://www.xcellence-it.com/ Xcellence IT

    How can I add multi level dropdown to this menu ? Any example… will be better…

    Thanks

  • http://www.goodstuff.hu Peter Nagy

    Good Stuff!

    Thanks

  • http://www.onlinetutorials4free.com sajan kota

    Looks awesome, Excellent work.

  • mansour

    thanx alot jef for the tutorial.

  • http://www.dsugroup.com.au Josh

    Great tut, this will definitely come in handy for one of our projects. Thanks!

  • http://www.aniqueahmad.com anique

    Great tutorial

  • http://www.freshclickmedia.com Shane

    Spastic nav? Unfortunately, Spastic’s meaning has evolved into something quite unsavoury in the UK: Spastic – Evolution of the term in the United Kingdom. I’m not offended at all by the way – good tutorial.

    • http://net.tutsplus.com Jeffrey Way

      Hey Shane – Sorry, I wasn’t aware. In America, it’s a very light and playful term. Maybe I should rename it.

      • http://www.freshclickmedia.com Shane

        Sidewalk/pavement etc. No problem with me. I was just surprised to see it, that’s all; I’d assumed it had the same meaning in America.

      • haroldo

        Probably worth changing the name! I would never say spastic as it’s pretty offesive to disabled people here in the uk…

    • http://www.nouveller.com/ Benjamin Reid

      Yeah, it kind of refers to someone who’s mentally disabled. I don’t take offence to it but someone might.

  • http://sonergonul.com Soner Gönül

    Wow

    That’s cool

    Thanks

  • http://www.codeworxx.de/ Sascha

    hmmm could someone tell my why my comment box is prefilled with

    Name: “Lars”
    Email: “the_llc@IDONTTELLYOU”
    URL: “http://hofinteractive.com”

    ??? This is not my Information and i have never entered!!! Think Nettuts has a Security Problem!

    Btw. the Tutorial is nice!

  • http://www.jeffadams.co.uk Jeff Adams

    Always nicei to see navigation tuts, some great use of jQuery to just add some spice to an otherwise boring element lol.

  • http://www.stephen-ainsworth.co.uk Stephen

    Yeah its a cool effect, but i’m not quite sure when/why you would use this. It seems a little overwealming for the user, but maybe I just like my sites more simplistic/minimual.

  • http://wptricks.net WP Tricks

    Lava-Lamp style menu is one of my favorite. The animation look smooth and nicely

  • http://www.nextgenwebmedia.com Grant

    Awesome tutorial- very well explained! I’m just a tad confused on where the size of the blob is generated from. Is it the CSS or the Javascript that changes the size of the actual blob?

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      The changes in width happen in the JavaScript file. When you hover over a new list item, the blob will receive that hovered item’s width and positioning (left) info.

  • http://jelmerdemaat.nl Jelmer de Maat

    Jelmer

  • http://www.monolithmultimedia.com Monolith Multimedia

    Nice tutorial

  • http://www.adslviettel.com viettel

    Thanks you very much, it’s so cool!

  • http://www.ChoiZ.Fr ChoiZ

    Video link appears down here (in France) :(

    blip.tv seems be down…

    Can you send us another link plz Jeffrey?

    Regards,

  • Milan

    Nice tutorial. Take a look at lava lamp menu I need recently at:

    http://www.monteagent.me

  • http://spotdex.com Davidmoreen

    That is really cool, I see these around a lot. I wonder if it is considered “web 2.0″

  • http://politique-du-possible.org mcgyver47

    Hi
    I would like to build a horizontal menu like this:
    http://www.lemonde.fr/
    when you hover a top list item it brings a horizontal list of submenu items and it stays as is untill you hover another top menu item
    Anybody an idea how to achieve this ?
    Thanks for a very good post as usual.
    Jean from France

  • Ruzwan

    Hi Jeff,

    Great tutorial ! I really appreciate your hard work.

    I have a question. If I click on any of the menu item and then move away my mouse from the menu then it goes back to Home. How can I force it to stay on the clicked item.

    Thanks !

    • http://www.jeffrey-way.com Jeffrey Way
      Author

      Youd have to remove the setTimeout section of the script. But are you sure that youd want?

  • gDinari

    Hey Jeff nice tutorial.

    I liked that is was easy to follow along with and more important, I could edit it too.

    I was wondering, how would I add a drop-down menu to it?

    Thanks, keep up the good work!

  • http://www.connormontgomery.com Connor Montgomery

    Jeff,

    Thanks for the great tutorial! I was also wondering how we could make it multi-level, if possible?

    Thanks again! Your tutorials are wonderful!

  • http://goodfoodpro.com Dan Sheetz

    Nice tutorial, thanks.

  • http://www.seowisedesigns.com Yheng

    By far, I prefer this lavalamp-style menu tutorial compare to others

  • http://blog.shpyo.net shpyo

    Is it saver way to use #selected, for telling script that element is selected? I think better way is use .selected instead of this. Anyway, nice tutorial :).

  • http://magpielab.com Team Magpie

    Superb one, really appreciate to publishing such a screen cast,

  • http://wwebz.com wwebz

    Hey

    Jef thanks for tutorial. I have seen such menu before at http://www.gmarwaha.com/blog/2007/08/23/lavalamp-for-jquery-lovers/ but you have explain everything in Very detail.

    Thanks

  • http://www.jordanwalker.net Jordan Walker

    Thanks for the excellent tutorial.