CSS+Javascript power. Fancy menu

Update: the code that empowers this menu has been upgraded to the latest MooTools version, and even improved! Now works with vertical, horizontal menus, with more flexible morphing!

Let me introduce you to Fancy Menu:

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:

Click here to see HTML code

  1. <div id="fancymenu">
  2. <ul>
  3. <li class="current" id="menu_home"><a href="#">Home</a></li>
  4. <li id="menu_plantatree"><a href="#">Plant a tree</a></li>
  5. <li id="menu_travel"><a href="#">Travel</a></li>
  6. <li id="menu_rideanelephant"><a href="#">Ride an elephant</a></li>
  7. </ul>
  8. </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:

Click here to see CSS code

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

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:

Click here to see CSS code

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

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:

Click here to see HTML code

  1. <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:

Click here to see CSS code

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

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.

Click here to see Javascript code

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

Click here to see Javascript code

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

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!

Fill in your name:

Select a picture:

505 Responses to “CSS+Javascript power. Fancy menu”

Pages: « 3433 32 31 30 29 [28] 27 26 25 24 231 » Show All

  1. 420
    Codebender » Blog Archive » Web Development Resources Says:

    [...] Fancy Menu with JavaScript and CSS [...]

  2. 419
    Adam Says:

    @Dada

    the e.stop() call is in main.js

  3. 418
    Adam Says:

    I was able to get this to work across most browsers, including the png AlphaImage hack for ie6. Here’s the trick though: usually we use the following hack settings for the ie6 png hack to work:

    #fancymenu .background .left {
    filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=image, src=’http://www.path.to/image/bg_menu.png’); background-image:none; overflow:hidden;
    }

    but if you change the sizingMethod to ‘crop’, the transparent bg image will allow itself to be sized and moved via js.

    a-like so:

    #fancymenu .background .left {
    filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(enabled=true, sizingMethod=crop, src=’http://www.path.to/image/bg_menu.png’); background-image:none; overflow:hidden;
    }

    It seems to work for me! Thanks, Guillermo!

    Adam

  4. 417
    Robert Brown Says:

    Guillermo - I tried this today with Mootools 1.2 beta (in compatibility mode even) and it did not work for me. It throws up lots of errors at this point. Would you mind reviewing it to see what changes may be needed to support Mootools 1.2?

    Thanks!

  5. 416
    Dada Says:

    Me again .. cannot be devthought.js, I’m not even calling it from the html file… now I’m totally lost :(

  6. 415
    Dada Says:

    Great menu!!

    I’m trying to make the links work, but I don’t know how to remove the e.stop() call. Where is it? Is in devthought.js? I think it’s in there, but I’m such a newbie..please help!

    Thanks in advance and congratulations for such a fantastic piece of work!

  7. 414
    link ekle Says:

    nice works , well, thanks.

  8. 413
    matt Says:

    great works… well…

  9. 412
    rjbrown99 Says:

    If you are using the latest mootools, 1.11 as of this post, you will need the following packages if you want to roll your own:

    Core
    Class
    Class.Extras
    Array
    String
    Function
    Number
    Element
    Element.Event
    Element.Filters
    Element.Selectors
    Window.DomReady
    Fx.Base
    Fx.CSS
    Fx.Styles
    Fx.Transitions

    And - very important - do not select the “Javascript Packer” - use the YUI compressor instead. This isn’t because of mootools, it is because a lot of the “bad guys” on the net are now using the javascript packer for malicious purposes to pack their spyware and malware.

    Why do you care? Because many companies are using automatic intrusion prevention systems on their network that auto-kill packed javascript for that purpose. So if you pack your Javascript, it may work but you may also inadvertently kill all of those functions for anyone browsing your site from behind a corporate firewall/ips system.

    It’s not because the packer won’t work - but the idea is that you *want* people to see your site, so please try to avoid dean edwards packer if you have widespread viewership as a site goal.

  10. 411
    Phil in Hong Kong − Web-dev Says:

    [...] for multiple selection. Swfupload and file upload in Yahoo UI rich text editor, a very slight menu slide. This entry was posted on Sunday, January 27th, 2008 at 12:43 pm and is filed under Software [...]

  11. 410
    MAG Says:

    Hi guys, and Guillermo.

    Guellirmo, as the link you gave at past (http://tangelo.blueorbs.com/share/slidelist5f5cb.zip), the menu item background seems black by IE7.

    But in your site, it seems like as it original, light gray. The Your original one and the example link are different I think ?

  12. 409
    JeremyVnc Says:

    How do you turn this menu into a Dropdown?

  13. 408
    Ben Says:

    For those of you having ‘Black’ problems in IE7, Josh solved it here - http://devthought.com/cssjavascript-true-power-fancy-menu/#comment-753 - by copying the CSS file from this page.

    The actual issue is that the ZIP version and the version on this page (http://devthought.com/wp-content/articles/fancy-menu/menu.css) is that the li background code is the difference, it’s missing the !important line which is needed for IE.

    Yours should be:

    #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 */

  14. 407
    Cele mai importante aplicatii pentru web designers - Clevetic Says:

    [...] CSS + Javascript Power - Un al fel de meniu. [...]

  15. 406
    13个效果超酷的Javascript网页导航菜单 | 帕兰卓一得 Says:

    [...] 8 ) LavaLamp jQuery Sliding Menu 一个基于jquery的滑动菜单效果,体积比较小巧。另一个版本是来自Guillermo Rauch基于mootools所构建的。 [...]

Pages: « 3433 32 31 30 29 [28] 27 26 25 24 231 » Show All

Leave a Reply