Better jquery mega-menu tutorial

My earlier simple mega menu implementation post displayed some simple css and jquery to explode a standard navigation menu into a mega-menu… I’ve made it even better. My biggest issue with that implementation was that it did not keep the order like you’d expect. It read left to right in columns rather than down each column. In the example you can see the first column of three would read from the top: a, d, g, j… this could potentially be confusing. So I wanted to update it to keep the order better and just stack the columns of elements rather than the elements themselves.

I used some different jquery to execute this. First we walk through the menu elements and calculate which column they should be in. We basically map that element’s (li)index to the column it should be, some big math. Luckily I had some experience from actionscript in my arsenal doing just that, so porting the function to javascript I was ready to go. If your number X falls between A and B, and you would like to convert it to Y which falls between C and D follow this formula: Y = (X-A)/(B-A) * (D-C) + C. Plugging this function in and cancelling out the zeros and adding some rounding to get integers I got: Math.floor((liindex / $total * $cols)+1). Using this I added a class to each ‘li’ designating which column it should be in, and then used wrapAll to wrap them into column divs. Very simple and a much better implementation overall anyways. Better code, better user experience… what more can you ask… so here’s the example and jquery code. I’m thinking I should make this into a jquery plugin or something, any thoughts?

better-mega-menu-screenshot

See the mega menu in action

Javascript code

jQuery(document).ready(function() {
    //clean up the row of the mega menu. add css class to each element on bottom row.
    //only if more than 7 elements. if more than 16, mm-3
    jQuery('#nav li ul').each(function(ulindex, ulele){
        $total = jQuery(this).children('li').size();
        if ($total <= 7) {
            jQuery(this).addClass('mm-1');
        }
        else {
            $cols = Math.floor(($total) / 8) + 1;
            $remainder = $total % $cols;
            $rows = Math.ceil($total / $cols);
            jQuery(this).addClass('mm-' + $cols + ' total-' + $total + ' rem-'+$remainder );

            jQuery(this).children().each(function(liindex, liele){
                //alert("total: "+$total+", remainder: "+ $mod+", ulindex: "+ulindex+", liindex: "+liindex);
                //If your number X falls between A and B, and you would like to convert it to Y which falls between C and D follow this formula: Y = (X-A)/(B-A) * (D-C) + C.
                jQuery(this).addClass('col-' + Math.floor((liindex / $total * $cols)+1) );
                if( (liindex+1) % $rows == 0) {
                    jQuery(this).addClass('last');
                }
            });

            for (var colcount = 1; colcount<= $cols; colcount++){
                jQuery(this).children('.col-'+colcount).wrapAll('<div class="col" />');
            }
        }
    });
});

css

ul { list-style:none; }

/********** < Navigation */
.nav-container { float:left; background: #398301; margin: 10em 0; width: 960px; }
#nav { border: 0px none; padding:3px 0 2px 44px; margin:0; font-size:13px; }

/* All Levels */
#nav li { text-align:left; position:relative; }
#nav li.over { z-index:999; }
#nav li.parent {}
#nav li a { display:block; text-decoration:none; }
#nav li a:hover { text-decoration:none; }
#nav li a span { display:block; white-space:nowrap; cursor:pointer; }
#nav li ul a span { white-space:normal; }

/* 1st Level */
#nav li { float:left; }
#nav li a { float:left; padding:5px 10px; font-weight:normal; color: #fff; text-shadow: 1px 1px #1b3f00; }
#nav li a:hover { color: #fff; text-shadow: 1px 1px 3px #ccc; }
#nav li.over a,
#nav li.active a { color:#fff; }

/* 2nd Level */
#nav ul { position:absolute; width:15em; top:26px; left:-10000px; border:1px solid #1b3f00; border-width: 0 1px 2px 1px; background:#398301; padding: 6px 0 6px; }
#nav ul div.col { float:left; width: 15em; }
#nav ul li { float:left; padding: 0; width: 15em; }
#nav ul li a { float:none; padding:6px 9px; font-weight:normal; color:#FFF !important; text-shadow: 1px 1px #1b3f00; border-bottom:1px solid #1b3f00; background:#398301; }
#nav ul li a:hover { color:#fff !important; text-shadow: 1px 1px 3px #ccc; background: #2b6301; }
#nav ul li.last > a { border-bottom:0; }
#nav ul li.last.parent > a { border-bottom:0; }

#nav ul li.over > a  { font-weight:normal; color:#fff !important; background: #1b3f00; }
#nav ul.mm-1 { width: 15em; }
#nav ul.mm-2 { width: 30em; }
#nav ul.mm-3 { width: 45em; }
#nav ul.mm-4 { width: 60em; }
/* 3rd+ leven */
#nav ul ul { top:-6px; background: #1b3f00; }

/* Show Menu - uses built-in magento menu hovering */
#nav li.over > ul { left:0; }
#nav li.over > ul li.over > ul { left:14em; }
#nav li.over ul ul { left:-10000px; }

/* Show Menu - uses css only, not fully across all browsers but, for the purpose of the demo is fine by me */
#nav li:hover > ul { left:0; z-index: 100; }
#nav li:hover > ul li:hover > ul { left:14em; z-index: 200; }
#nav li:hover ul ul { left:-10000px; }

Download

Visit this demo page and view source or save as…

This entry was posted in tutorial and tagged , , , , , , , , , , , , , , , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

3 Comments

  1. JavaFlactionscript
    Posted July 14, 2010 at 2:36 pm | Permalink

    Hey! I love the new design, it looks great. And I’m talking about both the blog and the menu. You’re my hero.

  2. Posted October 7, 2010 at 1:25 am | Permalink

    First of all, thanks for the code, been looking for 2 days.

    The code works well but I cant seem to get Magento to read the Javascript. I’ve placed the jquery.js and script everywhere and magento still cant seem to find it. At least that’s what I assumed as the category just wont move to the next column after added more than 10 of them.

    Any idea where’s the right place to place the script?

    • Posted October 7, 2010 at 2:39 pm | Permalink

      @Ashton – it looks like you’ve solved the issue? I was going to suggest that the css may be conflicting with something in your theme.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

  • Recent Posts

    WordCamp Presentation Slides: From Photoshop PSD to WordPress Theme

    Here are my slides for my WordCamp Atlanta presentation, From PSD to WordPress Theme: Under the skin: PSD to WP on Prezi Tweet

    wordpress_wordcamp_atlanta_2012_feb_2_3

    Speaker at WordCamp Atlanta 2012

    I’m proud to announce that I’ve been asked to speak at WordCamp Atlanta this year! WordCamp will be held this weekend and hosted at SCAD Atlanta! My session is titled: From PSD to WordPress Theme: Under the skin. Obviously, I’ll be focusing on themes. We’ll look at what they are, what they can do, how [...]

    Adobe-like Arrow Headers | CSS-Tricks

    Zero images is something that always gets me excited, I really like these arrow button styles! I like the css used more and the hover/active states too, nice css3 transitions. via Adobe-like Arrow Headers | CSS-Tricks. Tweet

    snow

    Snow via Javascript & Canvas – Tis the Season

    After playing with the settings in my experiments I found a few settings I liked and wanted to develop further. The first was snow! An added bonus I was able to work on a project just for the holidays and used much of this code in it! I looked around the web and saw a [...]

  • Recent Shares

    Link: Responsive Images: How they Almost Worked and What We Need

    Mat discusses the options for getting responsive images along with responsive designs. We can use various means (server-side, client-side, mobile-first, html5 data attributes, cookies…), but none are fully satisfactory, especially with new browsers prefetching images before cookies can be set or html is even fully read and parsed. He states that bandwidth sniffing is… a [...]

    Screen shot 2012-01-26 at 2.46.59 PM

    Yiibu – About the site…

    Here’s a great article about the process of responsive design & mobile first design and how to practically use them both in a project. This site is a proof of concept for many of the ideas described in Rethinking the Mobile Web or (Mobile First Responsive Design). via Yiibu – About this site…. Tweet

    gridpak

    Link: Introducing Gridpak | Erskine Labs

    Here’s a great tool to make responsive grid layouts. Thanks to Erskine Labs! Introducing Gridpak | Erskine Labs. Tweet

    css-multiply

    Link: HTML5 multiply filter with canvas | Alberto Gasparin

    Here’s a great little script I found useful today as I was working on having dynamic effects applied to javascript via canvas. “The canvas element provides scripts with a resolution-dependent bitmap canvas, which can be used for rendering graphs, game graphics, or other visual images on the fly.” Thanks to the canvas APIs I was [...]

  • Recent Comments

    Karl

    Karl

    I have been using for some time this nice Banner, from developer FX. They have a really nice Live...
    Karl

    Karl

    Thank you for this wonderful link… recommend it! Fast, simple, easy… :-)
    Gabriel

    Gabriel

    Hi Valerie, I don’t know if you are still following this post, but I tried seeing if it is...
    avinash

    avinash

    Hi Evan, I am using the same code and trying it on chrome/firefox it is not working on neither...
    Matt

    Matt

    I needed to store url variables from advertising tracking servers – this method works like a...
    Evan Mullins

    Evan Mullins

    @Saket – you may want to look into swfaddress. I believe it will be more what...