Simple Menu is a quick jQuery plugin which aims to be simple, minimally invasive, and provide non complicated, rudimentary functionality without bells and whistles. It is the very script used in this site to provide multilevel drop down menus.
Simple the options are the bare minimum necessary to adapt to the simplicity of needs, you may specify what type of trigger is used (click or hover) and specify callbacks to fire when displaying a menu or hiding a menu. That’s it. The rest of the styling is left up to you, however you decide to do it.
To activate it you’ll need specify the menu to call it upon and the script will handle the positioning:
$(function(){
$("ul#navigation").mainNav();
});
Refer to the tutorial in the Academy for more information on how it all works and what options are available. It will automatically find second level ul’s inside the children li’s of the top level ul#navigation and position them accordingly. Note that it expects and may even force some elements to relative positioning. Additionally it expects the top level navigation to be horizontal. Works well with my WordPress navigation menus.
The plugin script is as follows:
/**
* Protect namespace, etc
*/
(function ( $ ) {
/**
* create plugin for main nav stuff
*/
$.fn.mainNav = function( options ) {
// handle settings, if i had any
var settings = $.extend({
activator: 'hover',
callbackIn: null,
callbackout: null
}, options );
var showCMD = 'mouseover';
var hideCMD = 'mouseout';
if( settings.activator != 'hover' ){
showCMD = settings.activator;
}
// identify the nav item
var self = $(this);
// first hide children ul
self.find("ul").css("visibility","hidden");
// get all first level lis
var lis = self.find("li");
var tier = lis.find("li");
var top = self.children("li");
// fire first round positioning
var pos = function( self, sub, w, sw, h ) {
// do some edge detection
var ww = $(window).width();
// check for second tier
if( top.filter(self).length == 0 ) {
// detect edge collision and apply
if( ww < $(self).offset().left + w + sw ) {
w=-sw;
}
// standard tier correction to h
h = -h
// otherwise first tier
} else {
// edge detect
if( ww < $(self).offset().left + sw ){
// aligne right
w = w - sw;
} else {
w = 0;
}
// already at appropriate h
h = 0;
}
sub.css("marginLeft",w);
sub.css("marginTop",h);
};
// execute first round positioning
lis.each(function(){
var sub = $(this).children("ul");
// gather dimensions
var w = $(this).outerWidth();
var sw = sub.outerWidth();
var h = $(this).outerHeight();
// fire positioning on this object
pos( this, sub, w, sw, h );
});
// show child ul for hovering
lis.on(showCMD, function(){
var sub = $(this).children("ul");
sub.css("visibility","");
// gather dimensions
var w = $(this).outerWidth();
var sw = sub.outerWidth();
var h = $(this).outerHeight();
// fire positioning on this object
pos( this, sub, w, sw, h );
// execute callback in
if( settings.callbackIn !== null ){
settings.callbackIn(this);
}
}); // end of show function
// if not using click, use whatever is already specified
if( settings.activator != 'click' ){
lis.on(hideCMD,function(){
$(this).children("ul").css("visibility","hidden");
// execute callback out
if( settings.callbackOut !== null ){
settings.callbackOut(this);
}
});
// otherwise handle click out
} else {
$(document).click(function(e){
if( lis.has("ul:visible").has(e.target).length === 0 ){
lis.find("ul").css("visibility","hidden");
var tgt = lis.has("ul:visible");
// execute callback out
if( settings.callbackOut !== null ){
settings.callbackOut(tgt[0]);
}
}
});
}
};
})(jQuery);
CSS styling is up to you but I will provide what I put together for mine here. To be honest, it’s pretty straight forward.
#mainMenu ul, #mainMenu ul>li {
display: inline-block;
margin: 0;
padding: 0;
position: relative;
}
#mainMenu ul li a, #mainMenu ul li a:visited, #mainMenu ul li a:active
{
padding: 15px 10px;
display: block;
color: inherit;
}
#mainMenu ul li a:hover, #mainMenu ul li:hover {
background: beige;
color: #333;
text-decoration: none;
}
/** Second tier **/
#mainMenu ul li ul {
z-index: 99;
background: beige;
color: #333;
position: absolute;
/*right: 0;*/
}
#mainMenu ul li ul, #mainMenu ul li ul li {
display: block;
}
#mainMenu ul li ul li {
position: relative;
}
#mainMenu ul li ul li a {
display: block;
}
#mainMenu ul li ul li a:hover {
background: #FFC219;
border-radius: inherit;
}