From our sponsor: Elevate all your marketing with Mailchimp Smarts.
Today we want to share another menu experiment with you. For sure you are familiar with the off-canvas navigation on mobile apps and the implementations for responsive websites like the one by David Bushell. We tried to explore the possibility of creating a nested multi-level menu, something that could be quite useful for menus with lots of content (like navigations of online stores). The result is a “push” menu that can (theoretically) contain infinite nested sub-menus. When opening a sub-level, the whole navigation pushes the content more, allowing a slice of the parent menu to be visible. Optionally, this slice can be visible or not, in which case the sub-menu will simply cover its parent.
Working with nested structures is quite tricky because when we, for example, move the parent then all children will of course move as well. So we are using a couple of tricks that will maintain the right 3D translates for the sub-menus and their children. The main idea is to increment the value for the translate so that we guarantee that the sub-levels are not shown once we push everything a bit more for showing the slices of the parents. This is of course not necessary in the case where the sub-menu is covering the parent menu.
Please note that we are using 3D Transforms which only work in modern browsers. You will find a fallback example for non-supporting browsers in the end of the component.css file where we simply show the first level menu. The same we do for the no JS case.
We are using the following nested structure for the menu:
<!-- mp-menu --> <nav id="mp-menu" class="mp-menu"> <div class="mp-level"> <h2 class="icon icon-world">All Categories</h2> <ul> <li class="icon icon-arrow-left"> <a class="icon icon-display" href="#">Devices</a> <div class="mp-level"> <h2 class="icon icon-display">Devices</h2> <ul> <li class="icon icon-arrow-left"> <a class="icon icon-phone" href="#">Mobile Phones</a> <div class="mp-level"> <h2>Mobile Phones</h2> <ul> <li><a href="#">Super Smart Phone</a></li> <li><a href="#">Thin Magic Mobile</a></li> <li><a href="#">Performance Crusher</a></li> <li><a href="#">Futuristic Experience</a></li> </ul> </div> </li> <li class="icon icon-arrow-left"> <!-- ... --> </li> <li class="icon icon-arrow-left"> <!-- ... --> </li> </ul> </div> </li> <li><!-- ... --></li> <!-- ... --> </ul> </div> </nav> <!-- /mp-menu -->
…where each level is wrapped into a division with the class mp-level.
Normally, we would have used fixed positioning for a menu of this kind but since there is quite an peculiar “problem” with that (transforms will make it behave like an absolute positioned element), we’ll have to use absolute positioning which will leave us with some unwanted behavior of the site (scrolling of menu and dependence of document height). So we’ve used a little trick to avoid the menu being scrollable or to be cut off if the site’s content is too short by using the following page structure:
<div class="container"> <!-- Push Wrapper --> <div class="mp-pusher" id="mp-pusher"> <!-- mp-menu --> <nav id="mp-menu" class="mp-menu"> <!-- ... --> </nav> <!-- /mp-menu --> <div class="scroller"><!-- this is for emulating position fixed of the nav --> <div class="scroller-inner"> <!-- site content goes here --> </div><!-- /scroller-inner --> </div><!-- /scroller --> </div><!-- /pusher --> </div><!-- /container -->
Where we set the following styles for the elements:
html, body, .container, .scroller { height: 100%; } .scroller { overflow-y: scroll; } .scroller, .scroller-inner { position: relative; } .container { position: relative; overflow: hidden; background: #34495e; }
This will allow the content to be scrolled when the menu is closed and it will also make the menu being 100% of the window height. Basically, we are emulating what fixed positioning would do here.
This is how the plugin can be called:
new mlPushMenu( document.getElementById( 'mp-menu' ), document.getElementById( 'trigger' ) );
Or, if the submenus should cover the previous levels: new mlPushMenu( document.getElementById( 'mp-menu' ), document.getElementById( 'trigger' ), { type : 'cover' } );
For the demos we are using the beautiful Linicons iconfont by Sergey Shmidt created with the help of the IcoMoon app.
We hope you enjoy this menu and find it useful.
ML you rock!! This is Awesome.
Awesome menu. Looks nice.
Awesome !
Great work as always,
IMO Demo2 is more user friendly. 🙂
Thats Rock!
great this article 😉 thank for this 😉
AWESOME! as always!
Could you do a demo 3 – one with the first and second combined as I think that would be the best of both worlds!
Done! 🙂 Cheers, ML
Good call! Demo 3 is definitely the most user friendly of the bunch.
Could you do a demo with Scrolling? I cant scroll the Content or the Navigation if has more elements in
You can simply add
overflow:scroll
to the mp-level class. If you don’t want the scrollbar to be visible on browsers that show it like that, check out the Google Nexus menu and how we hide the scrollbar there with a wrapper technique. Hope it helps, cheers, MLI am having a ton of trouble getting this to work with scrolling. The Multi-Level Push Menu as it stands now is very slick… but unusable on mobiles due to the lack of scrolling.
I have tried working with the
overflow:scroll
as shown on the Google Nexus menu but haven’t had any luck yet. Is there a possibility I could get some help or a scrollable version of this awesome menu?Thanks!
Great article. Always something lovely
Hello, doesn’t work here, in FF 22.0, getting js error – “mlPushMenu is not defined”
Cheers.
Hi Mary, this is wonderful, I like the third but all are so great. Thank you.
This is a piece of art 🙂
Brilhante!
is amazing!!! =D
Superb! As usual.
oh, this is amazing
thanks
OMG, You are a goddess!!!
Excellent Work !
I’m looking for such a solution for a mobile only website, and the following code :
.scroller {
overflow-y: scroll;
}
made scrolling non native and very slugish on iOS.
So I replaced it with this code :
.mp-pushed .scroller {
overflow-y: scroll;
}
So that the fixed positioning behavior fix is only applied while the menu is opened. Works like a charm.
Hey Florian. I was running into the same problem when I applied this to a site I am working on. I tried your modified css and at first it solved the scrolling issue, but when I would switch back and forth from the slide-out menu the whole screen would go white. I haven’t been able to come up with anything to solve it. I was wondering if you ran into any similar issues?
Hi Curtiss,
Actually i went another way to get the “native scrolling” :
I’ve added the following css property to .scroller in the component.css file :
-webkit-overflow-scrolling:touch;
(Be aware that this is supported by iOS 5+). On Chrome Android Jelly Bean , it’s still a bit sluggish, I’m looking for a fix . On Android Stock Browser it works really good.
This is awesome might be perfect for a new project im working on, how would it render in an older browser though im curious. I know there are fallbacks but what would it appear like? I dont have any old IE on my mac so I cant tell. Thanks in advance!