Submit your widget

Mootools Elegant Menu Fly-out

Created 14 years ago   Views 10219   downloads 2010    Author chromasynthetic
Mootools Elegant Menu Fly-out
View DemoDownload
87
Share |

It’s a more elegant solution than regular fly-outs,Here is my version in JavaScript built with Mootools. Follow along as I describe the HTML, CSS, and JavaScript.

[Update: You can now try out and use the plugin version (MooTools | jQuery) of this tutorial if you want the effect without the work.]

The HTML

<div id="menu">
  <ul>
    <li class="first">
      <h2><a href="#">&gt; Menu 1</a></h2>
      <ul>
        <li class="first">
          <h3>Section 1</h3>
          <p>Here are a few links:</p>
          <ul>
            <li><a href="#">Link 1</a></li>
            <li><a href="#">Link 2</a></li>
            <li><a href="#">Link 3</a></li>
            <li><a href="#">Link 4</a></li>
          </ul>
        </li>
        <li>
          <h3>Section 2</h3>
          <p>Here are some more links:</p>
          <ul>
            <li><a href="#">Link 1</a></li>
            <li><a href="#">Link 2</a></li>
            <li><a href="#">Link 3</a></li>
            <li><a href="#">Link 4</a></li>
          </ul>
        </li>
        <li>
          <h3>Section 3</h3>
          <p>Even more links:</p>
          <ul>
            <li><a href="#">Link 1</a></li>
            <li><a href="#">Link 2</a></li>
            <li><a href="#">Link 3</a></li>
            <li><a href="#">Link 4</a></li>
          </ul>
        </li>
      </ul>
    </li>
    ...
  </ul>
  <div id="menu_content">
    <p>Other content that is still <a href="#">clickable</a>.</p>
  </div>
</div>

The structure is a little more complex than in previous examples. Essentially, we have three nested lists. The first list contains each menu section. The second list contains the submenu and it’s sections. The third list contains links that will be the actual navigation. Finally, there is a div that contains content that will be visible when no link is hovered over.

The CSS

* {
  margin:0;
  padding:0; 
}
#menu {
  width:720px;
  height:400px;
  overflow:hidden;
  margin:10px;
}
#menu ul {
  position:absolute;
  z-index:99;
}
#menu ul li {
  list-style:none;
  width:180px;
  float:left;
}
#menu ul li.first {
  border:0;
}
#menu ul li ul {
  overflow:hidden;
  width:178px;
  background-color:#cc6;
  border:solid #fff;
  border-width:0 2px;
  opacity: 0.75;
  -moz-opacity: 0.75;
  filter: alpha(opacity=75);
}
#menu ul li.first ul {
  width:180px;
  border-left:0;
}
#menu ul li ul li {
  padding:10px;
  border-top:solid 1px #fff;
  font-size:0.8em;
  font-family:Arial, sans-serif;
}
#menu ul li ul li.first {
  border:0;
}
#menu ul li ul li h3 {
  font-size:1.2em;
}
#menu ul li ul li ul {
  position:relative;
  border:0;
}
#menu ul li ul li ul li {
  font-size:0.9em;
  padding:0 0 0 15px;
  line-height:1.3em;
  border:0;
  background:url(bullet.gif) no-repeat left center;
}
#menu ul li h2 a {
  display:block;
  padding:10px 5px;
  font-family:Arial, sans-serif;
  text-decoration:none;
  font-size:0.7em;
  font-weight:normal;
  color:#fff;
  background-color:#666;
  border:solid 2px #fff;
  border-width:0 0 2px 2px;
}
#menu ul li.first h2 a {
  border-left:none;
}
#menu ul li.hover h2 a {
  background-color:#663;
}
#menu_content {
  background: url(menu.jpg) no-repeat center;
  height:100%;
  padding:3em 1em 1em 1em;
  color:#fff;
}

The CSS is also a bit complex because we have so many lists to style. What’s important is setting the display property of the first list to absolute so its children will drop over the div at the bottom. The z-index has to be set to a high number to account for a bug in Safari 3. Also, the image that you see is the background image of the last div #menu_content. Notice the opacity settings in #menu ul li ul. This ensures that the background image will at least be somewhat visible if JavaScript is disabled.

The JavaScript

var Menu = {
  start: function () {  
    var menu = $('menu');
    var img_opacity = new Fx.Style('menu_content', 'opacity', {'wait': false, 'duration': 400});
    menu.getFirst().addEvents({
      'mouseenter': function () {
        img_opacity.start(0.5);
      },
      'mouseleave': function () {
        img_opacity.start(1);
      }
    });
    menu.getFirst().getChildren().each(function (el) {
      var second_list = el.getElement('ul');
      second_list.setStyles({
        'opacity': 0,
        'height': menu.getStyle('height').toInt() - menu.getFirst().offsetHeight
      });
      var fx = second_list.effect('opacity', {'wait': false, 'duration': 200});
      el.addEvents({
        'mouseenter': function () {
          fx.start(1);
          this.addClass('hover');
        },
        'mouseleave': function () {
          fx.start(0);
          this.removeClass('hover');
        }
      }); 
    });
  }
};
window.addEvent('domready', Menu.start);

Pretty simple in comparison to the rest, eh? All we do here is make an opacity effect for the div with the background image and set mouseenter and mouseleave events on the main list that trigger the effect. (I did it this way because I didn’t like how the image would fade in and out again when moving from one menu item to another.) Then we iterate through the list items of the first list and get all the second lists, set their opacity to 0 and height to extend to the bottom of the container, and create opacity effects that will be triggered on the mouseenter/mouseleave events of their parent li elements. The hover class is also added to the li element so it still looks selected when the mouse is moved into the fly-out submenu. Finally, add the start function to the domready event of the window that Mootools supplies us with.

Modifications

When changing the width of the container, each individual menu section’s width has to be calculated manually and must account for any margin, padding, or border widths. It does take a little tweaking to get everything to line up perfectly.