CSS+Javascript power. Fancy menu

This post discusses a project which has its own page. Please refer to MorphList for the most up-to-date information.

Let me introduce you to Fancy Menu:

fancymenu

When it comes to creating the navigation part of your Website, the first thing you might think of is an unordered list that you style as tabs. Lately, such navbars are everywhere, as many people believe they’ll make their site more Web 2.0-compatible. Personally, I just think they’re semantically better and accessible.

In this article I’ll go through the creation of a custom navigation bar with some cute Javascript effects that will certainly impress your friends. Thanks to the great Mootools library, this beauty is contained in 1.5kb. Not only that, but it’s also cross browser (tested on Internet Explorer 6/7, Firefox and Safari) and accessible!

Introduction

Every time that I know I’m going to use Javascript to alter the behavior or look of something, I try to come up with a simple markup, and make sure it renders perfectly with Javascript turned off. To illustrate this point, imagine that you want to make an element wider on rollover. The property Javascript would change is width:, so I make sure first that my style works when I modify the width randomly.

For this menu, as we’ll be having a movable element that acts as the background, we should first make sure that just by using css, we can freely move it and that it won’t affect the display of the menu. If you didn’t do this, when you’re coding the JS and face a bug, you’ll find yourself wondering if it is caused by the CSS, the Javascript, the browser?

Mark it up

Just like any other navigation, we’re going to use an unordered list with some anchors:

<div id="fancymenu">
  <ul>
    <li class="current" id="menu_home"><a href="#">Home</a></li>
    <li id="menu_plantatree"><a href="#">Plant a tree</a></li>
    <li id="menu_travel"><a href="#">Travel</a></li>
    <li id="menu_rideanelephant"><a href="#">Ride an elephant</a></li>
    </ul>
</div>

This is the foundation of a semantically correct, degradable navigation structure.

The CSS styling

As I said before, it’s paramount that we create flawless, cross browser CSS code. Let’s get to it

The first problem we face is that it’s impossible to use the background property for the rounded box that follows your mouse, with the current CSS specs shared by most browsers. That forces us to add a new LI item that will act as the moving background.

We’re going to set position: relative to the unordered list, and position: absolute to the moving item, so that it’s easy to move it between the menu boundaries from Javascript. If you don’t quite understand how this works, I encourage you to quickly read this article about CSS positioning. You’ll understand that if we simply set position: absolute to it, we’d have to do some hard, useless calculations Javascript side to positionate it correctly.

Then, this is the code we have so far:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#fancymenu {
  position: relative;
  height: 29px;
  width: 421px;
  background: url('images/bg.gif') no-repeat top;
  padding: 15px;
  margin: 10px 0;
  overflow: hidden;
}
 
#fancymenu ul {
  padding: 0;
  margin: 0;
}
 
/* Don't apply padding here (offsetWidth will differ in IE)
If you need padding add it to the child anchor */
#fancymenu ul li {
  float: left;
  list-style: none;
}
 
#fancymenu ul li a {
  text-indent: -500em;
  z-index: 10;
  display: block;
  float: left;
  height: 30px;
  position: relative;
  overflow: hidden;
}

So far it’s quite easy, and I included some comments for the tricky parts. The text-indent property is used to hide the text without adding extra markup, and keeping it accesible.

Now, we have to add the background images for each link:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#menu_home a {
  width: 59px;
  background: url('images/menu_home.png') no-repeat center !important;
  background: url('images/menu_home.gif') no-repeat center; // ie!
}
 
#menu_plantatree a {
  width: 119px;
  background: url('images/menu_plantatree.png') no-repeat center !important;
  background: url('images/menu_plantatree.gif') no-repeat center;
}
 
#menu_travel a {
  width: 70px;
  background: url('images/menu_travel.png') no-repeat center !important;
  background: url('images/menu_travel.gif') no-repeat center;
}
 
#menu_rideanelephant a {
  width: 142px;
  background: url('images/menu_rideanelephant.png') no-repeat center !important;
  background: url('images/menu_rideanelephant.gif') no-repeat center;
}

In the following section you’ll see why we use .gif images for Internet Explorer by using the !important hack.

The moving background

As we discussed, there’s a LI that moves in a lower layer and stretches to take the shape of each element. Because of its structure, we’re going to implement something similar to the Sliding Doors technique, but without text.

Its markup would be the following:

<li class="background"><div class="left">&nbsp;</div></li>

As it doesn’t have any semantic role in the unordered list, we’re going to include it from Javascript. Of course, for testing, you can include it first manually and then remove it. This is the style for it:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#fancymenu li.background {
  background: url('images/bg_menu_right.png') no-repeat top right !important;
  background: url('images/bg_menu_right.gif') no-repeat top right;
  z-index: 8;
  position: absolute;
  visibility: hidden;
}
 
#fancymenu .background .left {
  background: url('images/bg_menu.png') no-repeat top left !important;
  background: url('images/bg_menu.gif') no-repeat top left;
  height: 30px;
  margin-right: 9px; /* 7px is the width of the rounded shape */
}

The use of this technique is one of the main reasons why we don’t use filters to display the PNGs in Internet Explorer. You can’t decide the position of the background with them, which would make the right corner side display above the left part. Read this article about the png hack limitations to find out more. Another reason is that Microsoft is updating users to IE7 automatically, which supports png perfectly.

Keep in mind, as well, that when you export the .gifs you’ll have to set the Matte to match the background color, otherwise everything will look really bad. This picture illustrates what your images should look like:

PNG and GIF comparison

Scripting it

Thanks to our smart CSS code, our Javascript is very short and simple. Its job is limited to adding the extra background markup, and of course the effects for shrinking and moving it.

We’re just going to need Mootools’ Fx.Style.js, Dom.js, and of course their dependencies. For this article’s example, I also used a custom transition found in the Fx.Transitions package (remember that transitions are what make the movement of the background vary). It’s coded in the form of a Class, so that it’s possible to initialize several menus on the same page.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
var SlideList = new Class({
	initialize: function(menu, options) {
		this.setOptions(this.getOptions(), options);
 
		this.menu = $(menu), this.current = this.menu.getElement('li.current');
 
		this.menu.getElements('li').each(function(item){
			item.addEvent('mouseover', function(){ this.moveBg(item); }.bind(this));
			item.addEvent('mouseout', function(){ this.moveBg(this.current); }.bind(this));
			item.addEvent('click', function(event){ this.clickItem(event, item); }.bind(this));
		}.bind(this));
 
		this.back = new Element('li').addClass('background').adopt(new Element('div').addClass('left')).injectInside(this.menu);
		this.back.fx = this.back.effects(this.options);
		if(this.current) this.setCurrent(this.current);
	},
 
	setCurrent: function(el, effect){
		this.back.setStyles({left: (el.offsetLeft)+'px', width: (el.offsetWidth)+'px'});
		(effect) ? this.back.effect('opacity').set(0).start(1) : this.back.setOpacity(1);
		this.current = el;
	},
 
	getOptions: function(){
		return {
			transition: Fx.Transitions.sineInOut,
			duration: 500, wait: false,
			onClick: Class.empty
		};
	},
 
	clickItem: function(event, item) {
		if(!this.current) this.setCurrent(item, true);
		this.current = item;
		this.options.onClick(new Event(event), item);
	},
 
	moveBg: function(to) {
		if(!this.current) return;
		this.back.fx.custom({
			left: [this.back.offsetLeft, to.offsetLeft],
			width: [this.back.offsetWidth, to.offsetWidth]
		});
	}
});
 
SlideList.implement(new Options);

Finally, it’s time to start it. Just create the object, by passing the id and desired options. The following example shows how to do it when the page DOM tree is loaded.

window.addEvent('domready', function() {
	new SlideList($E('ul', 'fancymenu'), {transition: Fx.Transitions.backOut, duration: 700, onClick: function(ev, item) { ev.stop(); }});
});

The script first looks for the element that has the current class. If it finds it, it positions the background behind it. If it doesn’t, it waits till the user first click on some item to set the ‘current’ class. This comes in very handy for menus meant for user selection, like the example below, instead of menus with links to actual URLs.

There’s an onClick option, which calls a function with an Event object, and the clicked element object reference as parameters. You can also change the effect duration, transition, etc.

Extend it

If you’ve made it this far, you must’ve noticed that it hasn’t been dead easy. In fact, the tutorial is not aimed solely to teach you how to create a menu, but for you to understand the possibilities you have using CSS and Javascript to make something stand out, and at the same time provide some tips to get you started if you want to create your own.

Here’s another example, using the very same Javascript class!

  1. good good good

  2. The fancy menu does not scroll as I rollover my menu. It only scrolls after I click on a button in the menu. Any suggestions?

    123candle.com/pet

  3. I did it!!!! heeeeey

    look at #menu li span
    Add a colortag there

  4. wats7@mail.ru
    - изготовление сайтов от 30$, баннеров от 10$
    - рассылка рекламы на 30000 русскоязычных форумов - 20$
    - рассылка рекламы на 1000 русскоязычных интернет досок - 7$
    - регистрация в 6000 русскоязычных каталогах - 7$
    - рассылка рекламы на 30000 англоязычных форумов - 20$
    -рассылка рекламы на тематические сайты (каталоги,доски и др.) - сбор базы
    + рассылка 60$. Следующие рассылки 10-20$.Собраные базы отдам Вам.
    -ручная рассылка рекламы на любые сайты интернета 0.2$ за каждую регистрацию (минимум 200 регистраций)
    -рассылка со скидками 100$ -то есть при заказе любых рассылок на общую сумму 150$ скидка 50$ подбор видов рассылок бесплатно
    -комплексная раскрутка сайтов 1000$ разовая + 100$ в месяц за рассылки или по договорености.
    Комплексная раскрутка расчитывалась на минимум 1000 уникальных в сутки,гарантии.
    -Рассылка на E-mail (только по Вашим базам подписчиков) 20$ на 150000 адресов. Можно на меньшие объемы но не меньше 10$
    -сбор баз любых сайтов или сбор информации.
    Изготовление сайтов, интернет-магазинов как на готовых шаблонах так и на шаблонах “с ноля”.
    На сайт можно поставить аудио,видео,слайдшоу,формы,регистрацию,фотогалерею,форум,
    гостевую,чат,блоги и другие возможости.Можно с панелью администратора и без.Можно заказать простые
    сайты 1 - 5 страниц текста с рисунками 10$-30$ есть более 100 простых шаблонов.
    - Много лицензионных программ (тысячи).
    wats7@mail.ru

  5. i’m using your app, thanks

  6. Good script, thanks

  7. Хороший скрипт, взял на заметку

  8. Я бы кое-чего добавил конечно, но по сути сказано все.

  9. Hello Dear.
    It’s a must appreciable attempt to write such an article. It helps us to build a nice one.

  10. awesome …!!!!!!!!!!!!!
    it’s work for me … thanks for share dude

  11. I will use this effect on your site.

  12. Thanks, very good!!

  13. It’s great menu.

  14. gash asne 4 months ago

    this is what i was looking for…great man..

  15. surferchick 4 months ago

    Hi there. Fancy Menu is great, but I am using it as part of the YooTheme - Shuffle and am struggling to change the menu font colours. I was able to change Item 1 to be black with a white hover and active .. but cant get beyond there
    If anyone has stumbled across this, would be great to here a work around
    cheers
    SC

  16. hi,

    it is not working for me give me any down load option or link, i have added this code in my html page it not working.

    ram.

  17. hi,

    it is not working please give me down load link i want to using for my site.

    Thanks.

  18. Hi

    Ive been trading forex for quite a while now. Ive learned from many sources and have read about forex programs that could
    make you great amounts of money perday.

    Ive looked through the web and see that there are so many programs but just dont know which one to choose.

    Ive also looked at clickbanks product and saw a while range of forex bot and automation stuff.
    Thus, I was wondering if any of you could point me to a good one.

    Also please provide some suggestion for which type as well.
    thanks very much
    ___________________________________________________________
    http://www.cbcommissions.com/flashcs/39/handle/random.gif

  19. jweis wu 6 months ago

    很好,我找的就是它

  20. Hi! My congrats on this very useful js! May I ask how you managed the bg.gif picture? I’d like to change it… how can I? thanks in advance! bye!

  21. Nicht schlecht, was da abläuft

  22. How i learn Jquery from ur website?
    Because i want to learn my self.

  23. How can i make good drop down menu by using css and javascritp?
    Your web is good.
    I can study drop down menu from ur website.
    Thank you!
    Good luck.

  24. This is a brilliant example of website navigation, would anyone know of a similar menu to this that uses the jQuery library? All my projects currently use jQuery so try not to mix and match up multiple libraries.

    Anyone tried making this style of menu with jQuery - if so i’d love to see what you have achieved.

  25. Excelent article!!! is Nice job!!! thanks for sharing

  26. Adam D'arcy 8 months ago

    Figured it out…
    $(function() {
    $(”#1, #2, #3″).lavaLamp({
    fx: “backout”,
    speed: 700,
    click: function(event, menuItem) {
    return false; //CHANGE THIS TO TRUE FOR LINKS TO WORK
    }
    });
    });

  27. Hi.. great looking menu and easily customizable.

    Mine won’t click though.. the anchors won’t work? Has anyone else had this problem? My site is http://dev01.knottedweb.com

    Thx ;o)

  28. Forgot to mention my links can either be normal anchor tags or ASP hyperlinks.

  29. Looks very interesting. Thanks for sharing..

    http://www.mpos.net/s/p1.asp

  30. Костя 9 months ago

    А по русски можно?

    • А по русски можно у меня глянуть! Я перевел статейку!

  31. Hello, this is a very nice tutorial, is there a lavalamp menu version with multi-level ?

  32. I loved Fancy menu and i am using in my web site. Thanks

  33. How to use this in wordpress themes?? Please help!

  34. Can anybody tell me how to use this effect with Wordpress themes?

  35. Thank you … this tutorial has me very helped.

  36. it’s a more and more popular menu effect now.

  37. Any way for vertical version ?