I have been loving the redesign of whitehouse.gov that coincided with Obama’s inauguration since, well, his inauguration. One of the things that impressed me the most is its navigational menu. It is a horizontal, pull-down style menu, but what is most interesting to me is the “mega” nature of the sub-menus.
It so happens that I am in the midst of designing a new website for the organization I work for, Northwest Federations of Community Organizations. As part of the process, one of the first steps I wanted to take was to attempt a navigational menu inspired by whitehouse.gov.
Here is a demo, and below are some notes on how I got there.
According to this site, my beloved menu is created using the Superfish jQuery plugin.
I visited the Superfish site and downloaded the zip archive. From the archive’s contents, I used the following:
- example.html
- superfish.css
- jquery-1.4.x.min.js
- hoverIntent.js
- superfish.js
- arrows-ffffff.png
- shadow.png
First, I customized example.html a bit.
I ended up overriding superfish’s default options by specifying the following:
<pre>
$(document).ready(function() {
$('ul.sf-menu').superfish({
delay: 500, // the delay in milliseconds that the mouse can remain outside a submenu without it closing
speed: 200, // speed of the animation. Equivalent to second parameter of jQuery's .animate() method
dropShadows: false, // completely disable drop shadows by setting this to false
});
});
</pre>
I changed the text of the navigation menu and sub-menus. I wanted to be able to quickly determine parent/child relationships and menu depth. As an example…
Top Level Navigation: A, B, C, etc…
2nd level navigation: A1, A2, A3, etc…
3rd level navigation: A1 A, A1 B, A1 C, etc…
The bulk of the customization happened in the style sheet, superfish.css.
First, I wanted my sub-menus to appear properly “mega.” That is, I wanted the width of the sub-menus to be generously oversized. To do so, I simply ensured that
.sf-menu ul { width: 20em; }
If I were to keep 3rd and 4th level menus, I would want to make sure that the 20em width was reflected in the appropriate classes.
ul.sf-menu li li:hover ul,
ul.sf-menu li li.sfHover ul { left: 20em; }
ul.sf-menu li li li:hover ul,
ul.sf-menu li li li.sfHover ul { left: 20em; }
The second thing I wanted to achieve was to ensure that 3rd and 4th level sub-menus are not visible. To do so, I commented out the following lines.
/* commenting this out, I don't want to see any ul 3 level items and deeper
ul.sf-menu li li:hover ul,
ul.sf-menu li li.sfHover ul {
left: 20em; /* match ul width
top: 0;
}
*/
/* commenting this out, it would apply to uls 4 levels deeper, but this is already inherited above
ul.sf-menu li li:hover li ul,
ul.sf-menu li li.sfHover li ul {
top: -999em;
}
ul.sf-menu li li li:hover ul,
ul.sf-menu li li li.sfHover ul {
left: 20em; /* match ul width
top: 0;
}
*/
Even though I hid the 3rd and 4th level menus, I was still left with the indicator arrow. To get rid of those unwanted arrows, I specified “background: none” in the following lines:
.sf-menu ul .sf-sub-indicator { background: none; }
.sf-menu ul a > .sf-sub-indicator { background: none; }
Next I wanted links in my sub-menu to appear as “columns.” To do so, I specified an approximate “halfway” width for the sub-menu’s list items.
.sf-menu li li { width: 45%; } /* places list items into "columns" */
After playing around with it, I wasn’t too happy with the way some of the longer list items clogged up the floated flow. The solution I found works wonderfully in Firefox, but alas not so well in Internet Explorer (surprised?). If anyone has a better solution, I would love to hear it.
.sf-menu li li:nth-child(odd) { clear: left; } /* this is important so that long items in 2nd level don't make floats weird looking, doesn't seem to work in IE */
The navigational menu still looks weird. I realized that much of this could be corrected through the use of colors, borders, etc…
I was feeling pretty good about the whole thing. But, while testing it all out, I realized that there was a large useability problem. When hovering over a main navigation item, a sub-menu normally appears below and to the right of it’s parent. What about if the parent was at the right-hand side of the screen?
Hover over “H” in example 7.
The folks behind whitehouse.gov solved this problem. The answer is that when a user hovers over a menu item that shows on the right half of the page, a sub-menu appears as normal, but pointed to the left, rather than to the right – as if each half of the navigational menu is a mirror image of the other half.
My implementation of whitehouse.gov’s solution is a little bit of a pain in the butt. If you have a suggestion for a better way, please do not hesitate to comment and share below! My solution was to ensure that top level menu items were assigned a unique id and assigned a specific width. Then that id was used in my CSS as follows:
/* for the right half of navigation; basically takes submenu and pushes it leftward, rather than rightward */
/* sucky thing is that need to specify id's */
#level-e ul,
#level-e:hover ul,
#level-e.sfhover ul,
#level-f ul,
#level-f:hover ul,
#level-f.sfhover ul,
#level-g ul,
#level-g:hover ul,
#level-g.sfhover ul,
#level-h ul,
#level-h:hover ul,
#level-h.sfhover ul {
left: -12em;
border: 0;
border-right: 1px solid #fff;
border-bottom: 3px solid #000;
}
and
.sf-menu > li { width: 10em; } /* this is necessary for implementing the right 1/2 of nav menu & it's submenu, otherwise don't know how much negative left positioning to apply */
Finally, I took the overall navigational menu and floated it left.
Was this exactly what you needed? Did this how-to suck? Did I leave something out? Do you have a better solution? Comment and share below!


12 Comments
Hey Dennis:
I’m doing something very similar, trying to add superfish drop-downs to a WP blog, and it just won’t show up. I saw your comment on ericmmartin.com’s article about using JQuery with WP and followed it here hoping you’d written about what you did to get it working, but alas, nothing. Any tips? I’ve followed Eric’s tips as far as I can understand them, but with no success. I also followed your ‘themocracy’ link but didn’t get much out of it. I’d be delighted if you had some tips…
Hi Mandel:
Thanks for commenting & asking a question. I sometimes wonder if anyone reads this blog, or if I’m just doing it for my own future reference. I hope the info below is helpful.
1) The key thing that was pointed out on ericmartin.com’s article is that you “enqueue” your javascript/jquery files.
Here’s what I have in my functions.php – it’s more than you need, but at least you can see my approach – also, make sure to look at the comments.
2) The relevant piece from the themocracy.com post is that you define the relative location of your theme files – this allows you to know that you’re “pointing” to the right place. I added this to my functions.php before the enqueue section above.
3. each of my customized javascript files has something like this at the top – here’s my nav.js – used not in the post above, but in a WordPress site I’m currently working on.
Also, the above post is based on a “proof of concept” type exercise I was doing. I wanted to see if I could pull off the navigation I wanted in the simplest way possible – using good, old plain html, css & javascript.
If so, the next step would be expanding the concept & trying to integrate it with WordPress, which I have since done, but have not posted anything about. Your question, Mandel, is inspiring me to write that post.
Thanks for getting back to me with such a comprehensive answer!
I’ve put the code into my functions.php page in the current theme, and it is generating links to both jquery and to the superfish.js file, but I still don’t get the drop-down. This does work on every regular page on the site, so I know that I have configured it correctly there; I assume this is a WordPress related conflict.
Two quick questions:
1. Did you customize superfish.js to add this:
jQuery(function ($) {/* You can safely use $ in this code block to reference jQuery */
});
in place of the ;function($){ which starts it off? If so, are you not meant to put all the code between the { brackets } ??
2. Do you use your custom js file instead of the standard block of script in the page itself? I was putting this in the header, but with no luck (and I did try wrapping it in the code block in my 1st question):
// initialise superfish
$(document).ready(function() {
$('ul.sf-menu').superfish({
autoArrows: false // disable generation of arrow mark-up
});
});
Sigh. This is one of those time-sucking things…
Actually, no – I didn’t alter superfish.js at all.
Oh, yes I created new javascript files. For the navigation, I titled it nav.js & referenced it in the enqueuing step:
// load nav.js -- the array ('jquery', 'hoverIntent', 'superfish') declares dependencies
wp_enqueue_script('nav', THEM_TEMPLATEURL.'/js/nav.js', array('jquery', 'hoverIntent', 'superfish'), '1.0', true);
Notice the version 1.0!
My first instinct was to put it in the header.php file, but after it didn’t work, I tried putting it as a separate .js file – and, thankfully, that did end up working.
I treated nav.js along the same “cascading” principle as CSS. My approach to javascript is very hack-y, I don’t really know it all that well.
I figured if you declare dependencies in the enqueing process, then maybe a “cascading” type principle, like CSS, would apply. First it would process jQuery. Then get supplemented by hoverIntent and Superfish. Finally, by my nav.js. If there was any conflict, then the newest in that stack would rule. Seems sound, right?
Well I have no idea if that “cascading” principle is correct or not, but the navigation ended up working.
Out of curiosity, do you have a URL I could look at where you trying this all out?
Thanks for the suggestions. I’ll try them and then get back to you with an URL if they don’t work. I do appreciate your time and thoughts on this!
This was just the thing at just the time — have been futzing around with a very similar thing and your left/right solution is elegant. (And, I saw your comment about visitors, so thought I’d let you know I was here. ;-) )
Thanks for commenting, visitor. I appreciate it. On the right/left thing, there’s probably a better way to achieve it, but thanks either way.
“When hovering over a main navigation item, a sub-menu normally appears below and to the right of it’s parent. What about if the parent was at the right-hand side of the screen?” I have been looking for a solution for this problem for days, and finally stumbled upon your solution, good work. I think you’re right, though, there’s probably a better / more efficient way to do it. If you do find a better solution, will you post here?
Hey Pete – yes, of course, I’ll post a better solution if I find it. And, thanks for the feedback. I’m currently working this into a custom WordPress theme. Luckily, WP assigns unique IDs to everything, including top-level menu items. This makes implementing this somewhat awkward solution easier.
I use a CMS that also assigns unique IDs to everything but doesn’t publish those ID’s on the frontend so it does make your solution difficult to implement using that CMS.
Not sure if you’ve already seen this…
http://users.tpg.com.au/j_birch/plugins/superfish/supposition-test/index.html
… but it looks like work on it has stalled since 2008.
No, I haven’t come across Supposition before. I wish I had played with it from the start. Thanks for sharing!