Multi-Level Push Menu

An experimental push menu with multi-level functionality that allows endless nesting of navigation elements.

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>
			<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>
						<li class="icon icon-arrow-left">
							<a class="icon icon-phone" href="#">Mobile Phones</a>

							<div class="mp-level">
								<h2>Mobile Phones</h2>
									<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>

						<li class="icon icon-arrow-left">
							<!-- ... -->
						<li class="icon icon-arrow-left">
							<!-- ... -->
			<li><!-- ... --></li>
			<!-- ... -->
<!-- /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">
			<!-- ... -->
		<!-- /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:

.scroller {
	height: 100%;

.scroller {
	overflow-y: scroll;

.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.

Tagged with:

Manoela Ilic

Manoela is the main tinkerer at Codrops. With a background in coding and passion for all things design, she creates web experiments and keeps frontend professionals informed about the latest trends.

Stay in the loop: Get your dose of frontend twice a week

👾 Hey! Looking for the latest in frontend? Twice a week, we'll deliver the freshest frontend news, website inspo, cool code demos, videos and UI animations right to your inbox.

Zero fluff, all quality, to make your Mondays and Thursdays more creative!

Feedback 261

Comments are closed.
  1. Thanks Mary Lou, Great post!

    I testing on chrome browser with link
    If I zoom small screen by press key crtl and “-” with 4 times, this menu have issue(Left site will blank 300px)
    In component.css will be action style:
    .no-csstransforms3d .mp-pusher, .no-js .mp-pusher{padding-left:300px;}
    My laptop screen(1366×768).

    Please, advice.

  2. Hey guys. Great menu, but I have a question. My JS chops are pretty weak and I’m wondering if there’s a way to have the first level of the menu load on page load, rather than on click of the trigger button. I’m not concerned with hiding the menu off screen at any time. I just want to be able to expose and close the other levels of the menu. Any help is greatly appreciated. Oh – I’m working with Demo 2 if that helps.

  3. Dear Sir/Madam,

    I am enquiring about the Vamtam Push Menu my theme is using on wordpress. I have been having a problem with my menu on a mobile device as the overlapping function overlaps the writing but with no extra background therefore, overlapping text onto text making it unreadable! I have tried to get help from my theme administrator but i wondered if you knew if there was anything i could do to stop this error.

  4. Hi,

    I got problem while closing the menu in IOS. its working in desktop and android phones. The menu is not getting closed once it is open in Iphone.
    Could you please help me to solve this problem?


  5. Need help ASAP,

    I try to scroll down the menu (My menu is higher than the device), but instead of the scroll is opened next menu level. How can I fix this thats when I touch move down/top menu should be scroll and when I touch should be open next level.
    Next case is that only the menu should by scrolled instead of his height. The page content should be not scrolled (always on top).

    • I found a solution, change:

      // event type (if mobile use touch events)
      this.eventtype = mobilecheck() ? ‘touchstart’ : ‘click’;


      // event type (if mobile use touch events)
      this.eventtype = ‘click’;

    • Excellent Dario, but instead, I would fix it more precisely by changing the appropriate listener.

      I changed
      el.querySelector( 'a' ).addEventListener( self.eventtype, function( ev ) {
      el.querySelector( 'a' ).addEventListener( 'click', function( ev ) {

      This way, you’ll keep ‘touchstart’ for the rest, which is more effective on mobile.

      If you want to keep your solution, I’d suggest that you also remove mobilecheck function to keep the code clean. * my 2 cents

  6. Not sure if anyone is following this thread any more since it is old…

    But, I have 2 fixed divs for a side navigation and a “back to top” button that work fine when the page loads. They stay still and work as intended. Once I click on this menu and then close it, those elements are no longer fixed. They start to scroll with the rest of the page. Is there a fix for this to get those elements to stay fixed when the menu is closed?

  7. Is there a way that has already been figured out to open the menu at a selected depth, e.g. on the page you are presently on.

    Menu 1 >> Menu 2 >> Menu 3 with current page in list.

    Open straight to Menu 3.

    Any thoughts?

  8. menu not working in landscape view and cant able to scroll up when menu list longer..especially on click slide next menu..any solution pls.. help..

  9. Has anyone gotten this menu to be accessible by using the keyboard tab button to navigate around?

  10. I’m having allot of trouble trying to add this to a rails project 🙁

    Love this menu though

  11. Hi,

    How can we make it possible to scroll the menu when there’re a lot of items or viewing it in landscape on a mobile device. Only 4-5 items are shown

  12. Wonderful menu! But I need some assistance. For the life of me, I cannot locate the CSS code that controls the horizontal lines that separate each menu item. Anyone that can help me with this? Thanks!

  13. It does not seem to work while testing in IE Developer Tools’ Emulation mode, especially when I select Browser Profile as ‘Windows Phone’. I also tested in Firefox and Chrome with User Agent Switcher plugin activated and it does seem to work there either. It seems to work fine on some of the real mobile devices I tested this on.

    I am a bit confused if this is going to be an issue ’cause I need to rely on emulators to test my front-end. Any specific reason that this is not working well with emulators or different user agents? I’ve never had this issue with other sliders I worked with.

  14. On the iPhone, in Safari, on most pages that scroll, once you scroll down a little bit, the address bar shrinks, and the bottom menu disappears. These re-appear when you scroll up a bit. But with this Multi-Push menu in place, none of that happens. The iPhone safari address bar doesn’t shrink, and the bottom menu stays visible the whole time. Has anyone found a fix for this? Thanks!

  15. Great menu system but I have notice a problem in Chrome due to the height:100% on html, body, .container, .scroller.

    I have divs on the page with background-attachment:fixed but this doesn’t work in Chrome, the background simply doesn’t display due to the fact that the container div(s) (.container & .scroller) have a height of !00% meaning that the background image on the div won’t show if the div is lower on the page than !00% of the browser height.

    I have been trying to create a workaround for this to work on Chrome but so far I have only been able to turn off background-attachment:fixed in Chrome and leave it on for other browsers.

  16. Thank you! It’s awesome. Just a small detail, there’s an extra DIV close tag in the article, below the comment. Thanks again.

  17. Hello,

    is it possible not show scroller in right sight (when si menu closed)? It always visible.

  18. Hi,
    Thanks for this amazing Push Menu !
    If you want to add a simple close button in it :

    Add this code (jquery) in your index for exemple :

    $( “#close_button” ).click(function() {
    $( “#trigger” ).get(0).click();

    And this code in the menu :

    <a href=”#” rel=”nofollow”>Close</a>

    Hope it help…

  19. Hi,

    Thanks for providing this excellent plugin. Really appreciable! Thanks for providing it free.

    Best Regards

  20. Hi,

    Great job and thank you!. One question: how can I make it open on desktop and just with the hamburger on mobile?

    would be nice!

    best regards

  21. Hello Mary Lou,

    Excellent Menu! I love it, you are very creative, and I love that! I was just playing around with your Multi Level Push Menu and I have it working, but…I have a question, which may lead to a few more…

    1. How do I remove the side pane next to the push menu so I can move my website content up that is below the push-menu?
    2. I have tried in the css file to adjust the height, but that only appears to affect the push-menu itself.

    • Mary Lou,

      I have tried wrapping my main_container div around the ml-push menus container and my website content does move up, however, the trigger menu height is messed up. I have tried height: auto, and height: 100% in the css for the ml push menu. Do you know what could be the issue?

      Thank you

  22. I it possible to put the html code for the menu in an external html document and load it on every page?