Blog (my web musings)

Find out what's interesting me, get tips, advice, and code gems that don't fit elsewhere.


Search Blog


Hidden side menus, like the ones used in Facebook and YouTube apps, are a space-saving alternative to traditionally visible desktop menus. This post introduces an upgrade to the earlier CSS-only off-canvass menu, that makes it possible for IE7/8 users to enjoy this menu too.

All the features are the same as the CSS-only version - the difference here is that JavaScript makes it compatible with earlier versions of Internet Explorer (IE7/8).

CSS3 Multi-Level, Off-Canvass Mobile Menu (with JavaScript IE7/8 support):

Demo

Now, because this menu builds upon the CSS-only version, it continues to use the checkbox hack, which is what makes functionality possible, without JavaScript, in modern browsers. But, the checkbox hack doesn't work in IE8 and earlier because the ":checked" pseudo class is unsupported in IE before version 9. So, for IE7/8 support, we must do something different - I decided to toggle a class on active menus, styling them open and closed, when needed, with CSS.

Adding JavaScript

Here's the goNav() JavaScript function that toggles the additional class. "sub-nav" is the default class that is always present, and "nav-ie" is an additional class that is added and removed onclick;

function goNav(nav){ 
    document.getElementById(nav).className = (document.getElementById(nav).className == 'sub-nav nav-ie') ? 'sub-nav' : 'sub-nav nav-ie';
    }

You can see how this 'nav-ie' class is used in the CSS, inside an IE conditional stylesheet. Remember that CSS transforms are not supported in these early versions of IE, so they get a basic left position switch - no slinky slide effect, but at least the menus are made visible (they are initially hidden "off-canvas" with a negative left position of -13.75em);

<!--[if lt IE 9]> 
<style>
#menu ul { margin-left:0 }
#menu.nav-ie, #menu .nav-ie { left:0 }
#container.nav-ie { position:relative; left:13.75em }
</style>
<![endif]-->

So, when the "nav-ie" class is present, the sub-menu is made visible, and when it is removed the sub-menu is hidden again.

The rest of the JavaScript ties the goNav() function to all the sub-menu's "toggle" ◄ and "toggle-sub" ► arrow labels so that the "nav-ie" class is added and removed onclick;

var sub = document.getElementById('menu').getElementsByTagName('label'); 
for(var i = 0; i < sub.length; i++){
    if(sub[i].className == 'toggle-sub'){ // forward '>' arrow label
       sub[i].onclick = function(){
           var chkbox = this.nextSibling;
           while (chkbox.nodeType != 1){ chkbox = chkbox.nextSibling; }
           var subNav = chkbox.nextSibling;
           while (subNav.nodeType != 1){ subNav = subNav.nextSibling; }
           goNav(subNav.id);
           }
        }
    if(sub[i].className == 'toggle'){ // back '<' arrow label
       sub[i].onclick = function(){
           goNav(this.parentNode.parentNode.id);
           }
        }
    }

Finally, the existing uncheckboxes() function that closes all sub-menus in one go in modern browsers, now carries a bit of extra JavaScript to remove all instances of the "nav-ie" class, which again, closes all sub-menu in one go, but for IE7/8;

function uncheckboxes(nav){ 
    var navarray = document.getElementsByName(nav);
    for(var i = 0; i < navarray.length; i++){
       navarray[i].checked = false
        }
    var navIE = document.getElementById('menu').getElementsByTagName('ul');
    for(var i = 0; i < navIE.length; i++){
       navIE[i].className = navIE[i].className.replace(/\bnav-ie\b/, '');
       }
    }

That's the sub-menus dealt with. To completely close the menu and return it to it's hidden, "off-canvass" state, I'm going to call the goNav() JavaScript function on the × labels - there's one right after the opening #menu div, and another just before the closing #menu div - they'll end up looking something like this;

    <label class="toggle close-all" onclick="uncheckboxes('nav'); goNav('menu'); goNav('container')">&times;</label>
</div><!-- closing "#menu" -->

But wait! It's all well and good talking about how to open and close sub-menus in IE7/8 with JavaScript and classes, but I haven't actually yet covered the very first step of opening the menu from its "off-canvass" position! That's very easy to handle when JavaScript is enabled - just put the goNav() function on the ☰ icon;

<label for="main-nav-check" class="toggle" onclick="goNav('menu'); goNav('container')" title="Menu">&#x2261;</label>

Problems arise when JavaScript is disabled though - those IE7/8 users won't be able to access the menu at all, so I propose this workaround; Use <noscript> tags to serve a static link to your website's sitemap;

<label for="main-nav-check" class="toggle" onclick="goNav('menu'); goNav('container')" title="Menu">&#x2261;</label>
<!--[if lt IE 9]><noscript><a class="toggle" href="/site-map.php">&#x2261;</a></noscript><![endif]-->

And mimic the existing ☰ icon with this CSS in the IE7/8 conditional styles;

#header a.toggle { padding:0 0.125em; font:2.875em/1.4375em Arial; text-decoration:none }

Compatibility

Modern browsers and IE9+ both with and without JS, and IE7/8 users with JS enabled (noscript workaround suggested above though). No slide effect in IE7/8/9.

View the source code of the demo page to grab the JS, CSS and HTML, and use wherever you like (with notices intact in the CSS).