Responsive Dropdown Multi-Level Menu

Creating a responsive menu seems something really easy until you start getting into responsive multi-level dropdown menus. There are hundreds of plugins out there that can do it for you but you do not always need them (as good as some of them are), you can quite easily create one yourself without a lot of code.

How? Well let me show you.

First let’s mark up a fairly standard html menu, although I will add a few classes straight away with some forward thinking in mind. We will add the classes of “menu” obviously and then “has-sub-menu” for any menu items that have a sub-menu, then a class of “sub-menu” pretty standard stuff. We will also add a link for the menu button above the <nav> this will be the trigger for activating the mobile menu. As you can see we have a good mix of 1 level dropdowns and 2 level dropdowns and a fairly big menu.

<a href="#menu" class="menu-link">Menu</a>
        
        <nav class="menu" id="menu">
            <ul>
                <li class="has-sub-menu"><a href="#">main menu 1</a>
                    <ul class="sub-menu">
                         <li><a href="#">sub menu 1</a></li>
                         <li class="has-sub-menu">
                            <a href="#">sub menu 2</a>
                            <ul>
                                <li><a href="#">sub sub menu 1</a></li>
                                <li><a href="#">sub sub menu 2</a></li>
                            </ul>
                         </li>
                         <li><a href="#">sub menu 3</a></li>
                         <li><a href="#">sub menu 4</a></li>
                         <li><a href="#">sub menu 5</a></li>
                         <li><a href="#">sub menu 6</a></li>
                         <li><a href="#">sub menu 7</a></li>
                         <li><a href="#">sub menu 8</a></li>
                         <li><a href="#">sub menu 9</a></li>
                    </ul>
                </li>
                <li class="has-sub-menu"><a href="#">main menu 2</a>
                    <ul class="sub-menu">
                        <li><a href="#">sub menu 1</a></li>
                        <li><a href="#">sub menu 2</a></li>
                         <li><a href="#">sub menu 3</a></li>
                         <li class="has-sub-menu">
                            <a href="#">sub menu 4</a>
                            <ul>
                                <li><a href="#">sub sub menu 1</a></li>
                                <li><a href="#">sub sub menu 2</a></li>
                                <li><a href="#">sub sub menu 3</a></li>
                                <li><a href="#">sub sub menu 4</a></li>
                                <li><a href="#">sub sub menu 5</a></li>
                            </ul>
                         </li>
                         <li class="has-sub-menu">
                            <a href="#">sub menu 5</a>
                            <ul>
                                <li><a href="#">sub sub menu 1</a></li>
                                <li><a href="#">sub sub menu 2</a></li>
                                <li><a href="#">sub sub menu 3</a></li>
                                <li><a href="#">sub sub menu 4</a></li>
                            </ul>
                         </li>
                         <li><a href="#">sub menu 6</a></li>
                         <li class="has-sub-menu">
                            <a href="#">sub menu 7</a>
                            <ul>
                                <li><a href="#">sub sub menu 1</a></li>
                                <li><a href="#">sub sub menu 2</a></li>
                                <li><a href="#">sub sub menu 3</a></li>
                            </ul>
                         </li>
                         <li><a href="#">sub menu 8</a></li>
                         <li><a href="#">sub menu 9</a></li>
                         <li><a href="#">sub menu 10</a></li>
                         <li><a href="#">sub menu 11</a></li>
                    </ul>
                </li>
                <li class="has-sub-menu"><a href="#">main menu 3</a>
                    <ul class="sub-menu">
                         <li class="has-sub-menu">
                            <a href="#">sub menu 1</a>
                            <ul>
                                <li><a href="#">sub sub menu 1</a></li>
                                <li><a href="#">sub sub menu 2</a></li>
                                <li><a href="#">sub sub menu 3</a></li>
                                <li><a href="#">sub sub menu 4</a></li>
                            </ul>
                         </li>
                         <li class="has-sub-menu">
                            <a href="#">sub menu 2</a>
                            <ul>
                                <li><a href="#">sub sub menu 1</a></li>
                                <li><a href="#">sub sub menu 2</a></li>
                                <li><a href="#">sub sub menu 3</a></li>
                                <li><a href="#">sub sub menu 4</a></li>
                                <li><a href="#">sub sub menu 5</a></li>
                                <li><a href="#">sub sub menu 6</a></li>
                            </ul>
                         </li>
                         <li class="has-sub-menu">
                            <a href="#">sub menu 3</a>
                            <ul>
                                <li><a href="#">sub sub menu 1</a></li>
                                <li><a href="#">sub sub menu 2</a></li>
                            </ul>
                         </li>
                         <li class="has-sub-menu">
                            <a href="#">sub menu 4</a>
                            <ul>
                                <li><a href="#">sub sub menu 1</a></li>
                                <li><a href="#">sub sub menu 2</a></li>
                                <li><a href="#">sub sub menu 3</a></li>
                            </ul>
                         </li>
                         <li class="has-sub-menu">
                            <a href="#">sub menu 5</a>
                            <ul>
                                <li><a href="#">sub sub menu 1</a></li>
                                <li><a href="#">sub sub menu 2</a></li>
                                <li><a href="#">sub sub menu 3</a></li>
                            </ul>
                         </li>
                         <li class="has-sub-menu">
                            <a href="#">sub menu 6</a>
                            <ul>
                                <li><a href="#">sub sub menu 1</a></li>
                                <li><a href="#">sub sub menu 2</a></li>
                            </ul>
                         </li>
                         
                    </ul>
                </li>
                <li class="has-sub-menu"><a href="#">main menu 4</a>
                    <ul class="sub-menu">
                         <li><a href="#">sub menu 1</a></li>
                         <li><a href="#">sub menu 2</a></li>
                         <li><a href="#">sub menu 3</a></li>
                         <li><a href="#">sub menu 4</a></li>
                    </ul>
                </li>
                <li class="has-sub-menu"><a href="#">main menu 5</a>
                    <ul class="sub-menu">
                         <li><a href="#">sub menu 1</a></li>
                         <li><a href="#">sub menu 2</a></li>
                         <li><a href="#">sub menu 3</a></li>
                    </ul>
                </li>
            </ul>
        </nav>

Now let’s style it up. Again nothing too out of the ordinary, just some styles to add some colours, styles to get the main menu items to sit alongside each other and then the drop downs to appear below the hovered item and then the second level items to appear next to the sub menu item. The only extra nice style added is a little animation just to make it appear nicely and this will also come in handy for the responsive version later.

.menu-link { display: none;}
.menu { 
  float: left;
  -webkit-transition: all 0.3s ease;  
  -moz-transition: all 0.3s ease;
  -ms-transition: all 0.3s ease;
  transition: all 0.3s ease; 
}
.menu ul { 
  padding: 0px;
  margin: 0px;
  list-style: none;
  position: relative;
  display: inline-table;
}
.menu > li > ul.sub-menu {
    min-width: 10em;
    padding: 4px 0;
    background-color: #f4f4f4;
    border: 1px solid #CCC;
}
.menu ul li { padding: 0px; }
.menu > ul > li { display: inline-block; }
.menu ul li a { display: block; text-decoration: none; color: #000; font-size: .9em; }
.menu ul li > a { padding: 19px 12px; }
.menu ul ul { 
  display: none; 
  position: absolute; 
  top:100%;
  min-width: 160px;
  background-color: #f4f4f4;
  border: 1px solid #CCC;
}
.menu ul li:hover > ul { display: block; }
.menu ul ul > li { position: relative; }
.menu ul ul > li a { padding: 5px 15px 5px 10px; height: auto; background-color: #f4f4f4; }
.menu ul ul > li a:hover { background-color: #42BBA3; color: #fff; }
.menu ul ul ul { position: absolute; left: 100%; top:0; }

Now let’s get the responsive styles in place. The media query size is up to you for your project and when you want it to kick in, but I am using 768px. Again nothing too special here the only thing to note is the max-height declerations this menu will slide open from a zero height. This for me is a better way than having the menu diplay none and display block or such like, as then that becomes trouble if you go from the mobile menu to the full menu and your hover effects still not working as it has display none from closing it on mobile etc etc. As you will also see there are a few styles in there for :after the .has-sub-menu containign link tags so it adds a little plus sign for users to know this is expandable and then when the menu is active (this will be shown how below) it will give them a little minus sign to know it can be shrunk back up. Other than that it is changing the position attributes as we obviously do not need them to be absolute anymore and appear when you hover below etc, plus changing some of the display attributes so they become blocks:

@media all and (max-width: 768px) {
  a.menu-link { display: block; color: #fff; background-color: #333; float: right; text-decoration: none; padding: 19px 10px;}
  .menu { clear: both; min-width: inherit; float: none; }
  .menu, .menu > ul ul { overflow: hidden; max-height: 0; background-color: #f4f4f4; }
  .menu > li > ul.sub-menu { padding: 0px; border: none; }
  .menu.active, .menu > ul ul.active { max-height: 100%; }
  .menu ul { display: inline; }
  .menu > ul { border-top: 1px solid #808080; }
  .menu li, .menu > ul > li { display: block; }
  .menu li a { color: #000; display: block; padding: 0.8em; border-bottom: 1px solid #808080; position: relative; }
  .menu li.has-sub-menu > a:after {
    content: '+';
    position: absolute;
    top: 0;
    right: 0;
    display: block;
    font-size: 1.5em;
    padding: 0.55em 0.5em;
  }
  .menu li.has-sub-menu > a.active:after {
    content: "-";
  }
  .menu ul ul > li a { background-color: #e4e4e4; padding: 19px 18px 19px 30px; }
  .menu ul ul, .menu ul ul ul { display: inherit; position: relative; left: auto; top:auto; border:none; }
}

Now to add a tiny bit of jQuery so that it can activate the menu’s by adding the class active to the menu and the sub-menu selected items. This will then apply the css rules to change the heights and the symbols from plus to minus etc.

$(document).ready( function(e) {

    var $menu = $('#menu'),
      $menulink = $('.menu-link'),
      $menuTrigger = $('.has-sub-menu > a');

    $menulink.click(function(e) {
        e.preventDefault();
        $menulink.toggleClass('active');
        $menu.toggleClass('active');
    });

    $menuTrigger.click(function(e) {
        e.preventDefault();
        var $this = $(this);
        $this.toggleClass('active').next('ul').toggleClass('active');
    });
    e.preventDefault();

});

Then that is about it you have a multi-level dropdown responsive menu without having to add in any heavy plugins and a much more maintainable easy to edit code base.

You can see a working example here. Feel free to take that source code and mess aorund with it achieving what you want.