Responsive CSS3 Multi-Level, Drop-Down Menu (with JavaScript enhancement)
This menu supersedes the earlier version that didn't support tap-activated sub-menus so well on touchscreen.
This responsive menu is a step on from the CSS3 Multi-Level, Off-Canvas Mobile Menu (with JavaScript enhancement) and provides both a mobile and desktop view of the menu.
It is also a progression of its CSS-only, responsive counterpart and uses only a teeny bit of JavaScript to close all the menus/sub-menus in one go in mobile view. This is a bonus over the CSS-only version where you have to close all opened sub-menus in turn. Please read the Notes section for details about JavaScript enhancement.
Desktop (> 960px): You'll see a familiar-looking horizontal, drop-down menu bar at the top of the screen...
Mobile (< 960px): Give that ☰ icon in the top-right corner a click to open the "off-canvas" menu...
Features
A CSS3, responsive menu that;
- Supports unlimited sub-menus, of infinite depth *
- Uses a nested list format
- Uses CSS3 transitions to animate the "off-canvas" slide effect (no JavaScript)
- Uses the "advanced checkbox hack" to activate "off-canvas" sub-menus (for Android/iOS)
- Uses "translate3d" to force hardware acceleration in WebKit (no flicker)
- Has a "Fly-Left" option to reverse the direction of drop-down sub-menus
- Has a "Go-Up" option to change the vertical direction of drop-down sub-menus
- Is only slightly enhanced with JavaScript and degrades gracefully with it turned off
* Although an infinite number of nested sub-menus is possible, you'll probably want to stop at 2 or 3 deep due to sub-menus progressively flying right in desktop view (see the "Fly-Left" section below for workaround).
Please view the source of this web page to grab the JS, CSS and HTML markup.
Fly-Left (desktop view)
OK, so sometimes you'll need a fly-out sub-menu from a button that's already close to the right-hand edge of the screen. No problem; a "fly-left" option is provided to reverse the direction of the fly-outs. The "JemCon.org > Previous JemCons" menu is an example of this.
To trigger the "fly-left" menu, just put a class of "fly-left" on the parent <li> tag;
<li class="fly-left"><a href="#">Previous JemCons</a> <label for="jemcon-previous" class="toggle-sub" onclick="">►</label>
<input type="checkbox" name="nav" id="jemcon-previous" class="sub-nav-check"/>
<ul id="jemcon-previous-sub" class="sub-nav">
<li class="sub-heading">Previous JemCons <label for="jemcon-previous" class="toggle" onclick="" title="Back">◄</label></li>
<li><a href="#">JemCon 2013</a></li>
<li><a href="#">JemCon 2012</a></li>
...
You can actually reverse the fly-out direction half-way through a series of nested sub-menus too, however, please be aware that on iPad (where the desktop menu is also likely to be visible), this can lead to the reversed fly-out sub-menus obscuring parent menu buttons. On a desktop PC this isn't a problem because the menus hide again once you hover away, but on touch-devices, hovers are replaced with clicks/taps so you cannot hover away to hide the menu. The only way to close an opened menu is to click/tap on another link, but you can tap-to-close drop-downs with JavaScript.
Go-Up (desktop view)
Long, nested drop-down menus will eventually fall off the bottom of the screen. To counter this, a "go-up" option is available to change the vertical direction of drop-downs. In otherwords, to make them go upwards. The "Focus on Function > Services" menu is an example of this.
To trigger the "go-up" menu, just put a class of "go-up" on the parent <li> tag;
<li class="go-up"><a href="#">Services</a> <label for="fof-services" class="toggle-sub" onclick="">►</label>
<input type="checkbox" name="nav" id="fof-services" class="sub-nav-check"/>
<ul id="fof-services-sub" class="sub-nav">
<li class="sub-heading">Services <label for="fof-services" class="toggle" onclick="" title="Back">►</label></li>
<li><a href="#">Content Management</a></li>
<li><a href="#">Graphic Design</a></li>
...
CSS Transforms and the "position:fixed" bug in Safari
When CSS Transforms are used (as this menu does), there is a known buggy behaviour in Safari that affects child "position:fixed" elements. What happens is that it seemingly forces them to adopt a "position:absolute" placement, while forcing their immediate parents to "position:relative". This causes some very strange (and frustrating) results. There is an easy fix here though - apply this CSS if you have any "position:fixed" elements inside ".container";
/* #### - corrects 'unfixing' bug in Safari - #### */
@media screen and (-webkit-min-device-pixel-ratio:0) { .container { -webkit-transform:none !important } }
Notes (JavaScript enhancement for mobile view)
The first change to the CSS-only version of the responsive menu is that all the checkboxes are named, e.g;
<input type="checkbox" name="nav" id="something-unique" class="sub-nav-check" />
And the bit of JavaScript below is used to remove all checks from checkboxes, thus closing all of the menus/sub-menus at once (in mobile view) instead of needing to close each in turn. I've also included a snippet that adds a class of "js" to the <html> element when JavaScript is enabled which, when coupled with the appropriate CSS, makes the menu degrade back to the CSS-only version when JavaScript is turned off;
<script>
document.documentElement.className = 'js'; // adds class="js" to <html> element
function uncheckboxes(nav){
var navarray = document.getElementsByName(nav);
for(var i = 0; i < navarray.length; i++){
navarray[i].checked = false
}
}
</script>
The JavaScript function is called inside an additional × label, placed just above the closing #menu div, which closes the menu and sends all mobile navigation back off-canvas. Note that there is no "for" attribute in the label - for some reason, things are a bit buggy with it included;
<label class="toggle close-all" onclick="uncheckboxes('nav')">×</label>
</div><!-- closing "#menu" -->
Now to make the new × label look pretty, and also move the large "back" ◄ arrows out of the way, add the following CSS to the mobile area of the stylesheet. Note the ".js" selectors that only apply when JavaScript is enabled;
#menu .close-all { display:none }
.js #menu .close-all { display:inline }
.js #menu .toggle { top:0; z-index:9999 }
.js #menu .sub-nav .toggle { left:0.15em; width:1em }
Finally, hide the × label when in desktop view by adding this to the desktop CSS;
.js #menu .close-all { display:none }
Compatibility
- Desktop: IE7+ (no down arrows in IE7/8) / Mobile: IE9+ (no slide effect in IE9) *
- Chrome
- Safari
- Firefox
- Opera
- Android
- iOS
* IE8 and under does not appear on any mobile device so the fact that the "off-canvas" mobile menu doesn't work there isn't really a problem. IE8 doesn't support media queries either so you can just serve an IE8 desktop stylesheet (with the desktop menu CSS) to those visitors.
Please be aware that touch screen desktop/tablet users have to tap the indicator arrows to open sub-menus, and drop-down sub-menus are likely to obscure page content until another link is clicked (see the iOS 'Sticky Hover' fix).
I haven't been able to test in other browsers/devices but feedback is always welcome. Contact me if you spot anything hinky.
Related
- Also see CSS3 Multi-Level, Off-Canvas Mobile Menu (no JavaScript)
- Also see CSS3 Multi-Level, Off-Canvas Mobile Menu (with JavaScript enhancement)
- Also see CSS3 Multi-Level, Off-Canvas Mobile Menu (with JavaScript IE7/8 support)
- Also see Responsive CSS3 Multi-Level, Drop-Down Menu (no JavaScript)
- Also see Responsive CSS3 Multi-Level, Drop-Down Menu (with JavaScript enhancement + keyboard 'tab-to' support)
- Also see Responsive CSS3 Multi-Level, Drop-Down Menu (SwiftClick - no 300ms delay + tap-to-close drop-downs)
- Also see Responsive CSS3 Multi-Level, Push/Slide Menu (no JavaScript)
- Also see Responsive CSS3 Multi-Level, Push/Slide Menu (with JavaScript enhancement)
- Also see Responsive CSS3 Multi-Level, Push/Slide Menu (with JavaScript enhancement + keyboard 'tab-to' support)
- Also see Responsive CSS3 Multi-Level, Fly-Out Menu (no JavaScript)
- Also see Responsive CSS3 Multi-Level, Fly-Out Menu (with JavaScript enhancement)
- Also see Responsive CSS3 Multi-Level, Fly-Out Menu (with JavaScript enhancement + keyboard 'tab-to' support)
Freebies
Looking for more freebies for your website? Grab a bunch of free PHP, CSS and JavaScript goodies, from flat file CMS' to RSS managers to responsive CSS menus, galleries and sliders.