Responsive Multi-Level Menu

A responsive multi-level menu that shows its submenus in their own context, allowing for a space-saving presentation and usage.
Responsive Multi-Level Menu

From our sponsor: Reach inboxes when it matters most. Instantly deliver transactional emails to your customers.

Today we want to share an experimental drop-down menu with you. The main idea is to save space for menus that have a lot of content and sub-levels. Each sub-level in this menu will be shown in its own context, making the “parent” level disappear. This is done with subtle animations that are defined in separate animation classes. The menu is fluid so that it can be used easily in a responsive layout.

Please note: this only works as intended in browsers that support the respective CSS properties.

The structure of the menu contains an unordered list that can have an arbitrary number of sub-lists:

<div id="dl-menu" class="dl-menuwrapper">
	<button class="dl-trigger">Open Menu</button>
	<ul class="dl-menu">
			<a href="#">Item 1</a>
			<ul class="dl-submenu">
				<li><a href="#">Sub-Item 1</a></li>
				<li><a href="#">Sub-Item 2</a></li>
				<li><a href="#">Sub-Item 3</a></li>
					<a href="#">Sub-Item 4</a>
					<ul class="dl-submenu">
						<li><a href="#">Sub-Sub-Item 1</a></li>
						<li><a href="#">Sub-Sub-Item 2</a></li>
						<li><a href="#">Sub-Sub-Item 3</a></li>
				<li><!-- ... --></li>
				<!-- ... -->
		<li><!-- ... --></li>
		<li><!-- ... --></li>
		<!-- ... -->
</div><!-- /dl-menuwrapper -->

Animations are defined in animation classes:

.dl-menu.dl-animate-out-1 {
	animation: MenuAnimOut1 0.4s linear forwards;

@keyframes MenuAnimOut1 {
	50% {
		transform: translateZ(-250px) rotateY(30deg);
	75% {
		transform: translateZ(-372.5px) rotateY(15deg);
		opacity: .5;
	100% {
		transform: translateZ(-500px) rotateY(0deg);
		opacity: 0;

.dl-menu.dl-animate-in-1 {
	animation: MenuAnimIn1 0.3s linear forwards;

@keyframes MenuAnimIn1 {
	0% {
		transform: translateZ(-500px) rotateY(0deg);
		opacity: 0;
	20% {
		transform: translateZ(-250px) rotateY(30deg);
		opacity: 0.5;
	100% {
		transform: translateZ(0px) rotateY(0deg);
		opacity: 1;

And the plugin is called as following:

$( '#dl-menu' ).dlmenu({
	animationClasses : { classin : 'animation-class-name', classout : 'animation-class-name' }

We hope you like this little experiment and find it inspiring!

Tagged with:

Mary Lou

ML is a freelance web designer and developer with a passion for interaction design. She studied Cognitive Science and Computational Logic and has a weakness for the smell of freshly ground peppercorns.

Stay up to date with the latest web design and development news and relevant updates from Codrops.

CSS Reference

Learn about all important CSS properties from the basics with our extensive and easy-to-read CSS Reference.

It doesn't matter if you are a beginner or intermediate, start learning CSS now.

Feedback 195

Comments are closed.
  1. In the stock version of this you can’t actually click the top level elements if they have children (because they automatically load the child menu).

    In case anyone needs it, I worked on a little addendum script that clones the parent link into the child so that you don’t need to double-post the parent links inside their child-menus (useful for, say, a WP theme version of this!).

    Link to the script and discussion:

    • Just a note – from a UI point of view, it’d actually make more sense for ONLY the arrow elements at the right-side of the bar to load the child-menus, not the entire bar… the actual top level parent links should still be clickable in my opinion.

      That said, I get why it’s done this way; the CSS :after selector isn’t clickable (that I know of) and it gets messy if you try to add the arrow as it’s own element.

      This is still an incredible little piece of work – I’m using it as a responsive-only menu on a site right now and it’s lovely now that I have the parent links nested as functional links inside their child menus 🙂

    • Brandon,
      Did you turn this menu into a wordpress version? If so, can you tell me how you did it. Thanks


    • Hello. I agree that is was much nicer and practical if the parent link was click-able. I am glad that someone thought of that but i wonder where did you put that piece of code? I have tried to put it in the jquery.dlmenu.js but nothing happened.

    • Forget the post before… i have found the location.
      uuups… you must double click the cloned item for it to work?

  2. Hello! How to replace “square with stripes” on the menu? To something else)

  3. Item li with class=”dl-back” must be added automatically to any ul class=”dl-submenu” , why not?

  4. In order to replace “square with stripes” edit blocks “.dl-menuwrapper button” and “.dl-menuwrapper button:after “in component.css

  5. Hello
    Is there any way to give a callback?
    I use along with your menu script a scroll bar that should be updated so that the submenu is called. Then once the submenu finish appears I have to give this bar an upgrade.

    Have any way to do this? A callback function?

  6. hey, is there any possible way to make it work on IE. at least functionally not visually. IE should be banned

    • Hello, I made it work fine in IE, at least version 8.x.
      See if you are not doing anything wrong.

  7. Hi

    And thanks for the awesome little menu, love it! One question, what do I have to do to make the whole menu align to right corner on the website so that the button is on the right top corner compared to the menu-wrapper. Have tried different ways of floating and setting left % values, but with no success 🙁 Thanks

    • Try this:

      $(“#dl-menu button”).offset({“top”:”0″, “left”: $(window).width()-50});

      In a similar way, you can move whole menus in the desired position.

  8. Hi, I don’t want to click on the button to see the menu. How can I change “jquery.dlmenu.js” right?

  9. Hello Mary Lou. Thanks for the input. As I can do to make it look in IE8? It really does display but the effects do not apply.

  10. Does anyone know of a good way to make the top level be clickable to another page? I am still trying to use this nav, but would like the top level to be a link instead of just opening the submenu.

  11. From an intuitive usability standpoint, I think the 2nd demo is the only workable one, given that clicking into a submenu motions right and clicking back into the parent menu motions left.

    AWESOME. Mary Lou #ftw!

  12. How should I display these menus without using the “Open Button” triggered? I mean, the menu is already displayed in the page when pages’ loads and we don’t need to click the menu icon to show up the menu? Please help!

    • Try this:


      .dl-menuwrapper button {
      background: #ccc;
      border: none;
      /* width: 48px; */
      height: 45px;
      /* text-indent: -900em; */
      /* overflow: hidden; */
      position: relative;
      cursor: pointer;
      outline: none;

      Also delete the “.dl-menuwrapper button:after” section.

      Add in script-section of index.html:

      $( ‘#dl-menu button’ ).on(‘mouseover’, function(){

      $( ‘#dl-menu button’ ).on(‘mouseout’, function(){

      Is that it?

  13. The demo doesn’t seem to be working right now (tested in the latest Chrome and FF)

    • Sorry about that! Updated and working now! Thanks for the feedback. Cheers, ML

  14. I can’t get this code works on my PC. Could someone please send me the files for the demo 1 only so I can study them?

    I mean the files without the unnecessary element for the demo 1 only.

    I will appreciate it so much.
    Thank you.


  15. Is there an easy way to make this a horizontal drop down menu on a desktop?

  16. Very nice, but unfortunately, without IE8 support it’s not very useful for websites that cater to the masses. IE8 is still a dominant browser, whether we like it or not. Here are my observations:

    Mostly functions in IE9+ except:
    1) No transition affects
    2) Back arrow shows as forward array

    On IE8 there are more problems:
    3) Main menu always shows and will not hide, regardless of clicking the “dl-trigger” button.
    4) Arrows do not display at all.

    #2 seems to be due to IE9 not supporting CSS rotate 180 degrees.
    #4 seems to be due to IE8 not supporting the custom font and the CSS a:not(:only-child)
    #1 is not too important, but #3 & #4 are show stoppers on IE8

  17. Thanks Mary Lou – I was looking for some form of navigation for a custom wordpress site that wasnt intrusive, and voila! you provided us with another amazing piece. Here it is in action Thanks again!

    • Christi – I just read the comment last night and made instructions have a quasi-plugin on my site – meaning that you have to add something else to your functions.php – check this linkand hope it helps someone – you may have to make some modifications for however you are using it, as I did this for a custom theme I was building.