Creating a Responsive Menu

In this tutorial, I'm going to show you how to create one of the responsive menus from our website. You can find the menu here. So, the final result will look like this:

Creating a Responsive Menu

The Markup

We're going to start with the HTML code. Our menus use nested unordered lists contained by a div.

<div id='cssmenu'>  
   <ul>
      <li><a href='#'>Home</a></li>
      <li><a href='#'>Products</a>
         <ul>
            <li><a href='#'>Product 1</a>
               <ul>
                  <li><a href='#'>Sub Product</a></li>
                  <li><a href='#'>Sub Product</a></li>
               </ul>
            </li>
            <li><a href='#'>Product 2</a>
               <ul>
                  <li><a href='#'>Sub Product</a></li>
                  <li><a href='#'>Sub Product</a></li>
               </ul>
            </li>
         </ul>
      </li>
      <li><a href='#'>About</a></li>
      <li><a href='#'>Contact</a></li>
   </ul>
</div>  

The menu uses our jQuery plugin which can be found here. Let's download jQuery and the plugin, then include them:

Now we initialize the plugin. Our plugin has three options: title (which will be the text of the button that toggles the menu on mobile devices), breakpoint (the screen width at which the menu will switch to its mobile mode, the default value being 768) and format (it can take three values and determines what type of menu we'll have on mobile devices). For this menu, the format option will take the value multitoggle, which means each submenu can be opened/closed on its own. The other two values of this option are dropdown (the entire menu, including the submenus, will be opened/closed with a single touch) and select (the menu will be displayed as a select list of mobile devices).

The CSS

Our menus use LESS for the menu builder, but we want to make this tutorial accessible for everybody, so I'm going to use vanilla CSS this time. I'm also not going to include all the options of the menu in the tutorial, it would just make it unnecessarily long. First, we're going to include a font from Google Fonts and use a stylesheet reset targeting all the elements used by our menu:

@import url(http://fonts.googleapis.com/css?family=Montserrat:400,700);
#cssmenu,
#cssmenu ul,
#cssmenu ul li,
#cssmenu ul li a,
#cssmenu #menu-button {
  margin: 0;
  padding: 0;
  border: 0;
  list-style: none;
  line-height: 1;
  display: block;
  position: relative;
  -webkit-box-sizing: border-box;
  -moz-box-sizing: border-box;
  box-sizing: border-box;
}

We use the stylesheet reset to prevent our menus from conflicting with other CSS from the user's page. Next, the clearfix:

#cssmenu:after,
#cssmenu>ul:after {
  content: ".";
  display: block;
  clear: both;
  visibility: hidden;
  line-height: 0;
  height: 0;
}

We don't need the button which toggles the menu on mobile devices, so we're going to hide it for now:

#cssmenu #menu-button {
  display: none;
}

The menu font and background color:

#cssmenu {
  font-family: Montserrat, sans-serif;
  background: #333333;
}

We need the menu items on the same line, so we'll float them to the left:

#cssmenu>ul>li {
  float: left;
}

Next, we'll style the main links (padding, typography, and transitions):

#cssmenu>ul>li>a {
  padding: 17px;
  font-size: 12px;
  letter-spacing: 1px;
  text-decoration: none;
  color: #dddddd;
  font-weight: 700;
  text-transform: uppercase;
  -webkit-transition: color .25s ease;
  -moz-transition: color .25s ease;
  transition: color .25s ease;
}

The links change their color on hover, going from a light gray to white:

#cssmenu>ul>li:hover>a {
  color: #ffffff;
}

The links which have submenus need extra space to the right of the submenu indicator. The list items which contain those links have a class called has-sub which is added by the jQuery plugin but can also by added by the menu builder.

#cssmenu>ul>li.has-sub>a {
  padding-right: 30px;
}

At this point, the menu should look like this:

Creating a Responsive Menu

Now let's create the submenu indicator, which will be a "+" symbol. On hover, the submenu will be displayed and the indicator will become a horizontal line/a single dash. We'll create the horizontal line first with an after pseudoelement. The line will be 8px wide and 2px high and must have the same color as the links.

#cssmenu ul>li.has-sub>a:after {
  position: absolute;
  top: 22px;
  right: 11px;
  width: 8px;
  height: 2px;
  display: block;
  background: #dddddd;
  content: '';
  -webkit-transition: background .25s ease;
  -moz-transition: background .25s ease;
  transition: background .25s ease;
}

Creating a Responsive Menu

On hover, the line changes its color just like the menu links:

#cssmenu>ul>li.has-sub:hover>a:after,
#cssmenu>ul>li.has-sub>a:hover:after {
  background: #ffffff;
}

The vertical line is next. We'll use a before pseudoelement this time:

#cssmenu ul>li.has-sub>a:before {
  position: absolute;
  top: 19px;
  right: 14px;
  display: block;
  width: 2px;
  height: 8px;
  background: #dddddd;
  content: '';
  -webkit-transition: all .25s ease;
  -moz-transition: all .25s ease;
  -ms-transition: all .25s ease;
  -o-transition: all .25s ease;
  transition: all .25s ease;
}

Creating a Responsive Menu

On hover, the vertical line will disappear. We'll do that by making its height 0. We'll also modify its vertical position to create a nice effect.

#cssmenu ul>li.has-sub:hover>a:before,
#cssmenu ul>li.has-sub>a:hover:before {
  top: 23px;
  height: 0;
}

The main menu is finished, it's time to move on to the submenus. They should be hidden by default:

#cssmenu ul ul {
  position: absolute;
  left: -9999px;
}

They will be displayed on hover:

#cssmenu li:hover>ul {
  left: auto;
}

The second level submenus will be displayed to the right of their parent. We'll use margin-left to push them to the right:

#cssmenu ul ul ul {
  margin-left: 100%;
  top: 0;
}

Now we're going to give the submenus a nice expanding effect when they are displayed. First, we give the height 0 to the list elements of the submenus. Then we use CSS transitions and bring them to their normal height, which is 35px.

#cssmenu ul ul li {
  height: 0;
  -webkit-transition: height .25s ease;
  -moz-transition: height .25s ease;
  transition: height .25s ease;
}

#cssmenu li:hover>ul>li {
  height: 35px;
}

The submenu links are not styled yet, so let's do that. Smaller font size and height than the main links, the same background and text color and a semi-opaque gray bottom-border. We're using this semi-opaque medium gray because this looks good and consistent regardless of the background color you choose in the menu builder.

#cssmenu ul ul li a {
  width: 170px;
  padding: 11px 15px;
  border-bottom: 1px solid rgba(150, 150, 150, 0.15);
  font-size: 12px;
  text-decoration: none;
  color: #dddddd;
  font-weight: 400;
  background: #333333;
}

On hover, the submenu links will change their text color just like the main links. Also, the last submenu link doesn't need the bottom-border.

#cssmenu ul ul li:last-child>a,
#cssmenu ul ul li.last-item>a {
  border-bottom: 0;
}

#cssmenu ul ul li:hover>a,
#cssmenu ul ul li a:hover {
  color: #ffffff;
}

The submenus look pretty good now:

Creating a Responsive Menu

As you can see, submenu links can also have submenu indicators which they inherited from the main links, but they are not positioned correctly. They also don't change their color on hover. You're probably wondering why they didn't inherit the hover color change from the main links. That's because in our menu builder the main links and the submenu links can have different colors and hover colors, so we have to make sure the indicators match each one of those colors.

#cssmenu ul ul li.has-sub>a:after {
  top: 16px;
  right: 11px;
  background: #dddddd;
}

#cssmenu ul ul>li.has-sub:hover>a:after,
#cssmenu ul ul>li.has-sub>a:hover:after {
  background: #ffffff;
}

#cssmenu ul ul li.has-sub>a:before {
  top: 13px;
  right: 14px;
  background: #dddddd;
}

#cssmenu ul ul>li.has-sub:hover>a:before {
  top: 17px;
  height: 0;
}

Creating a Responsive Menu

The design and functionality for big screens are finished, now we'll focus on the mobile design. The menus made to work with our jQuery plugin don't use media-queries. On mobile devices, the plugin adds a small-screen class to the cssmenu div, so we're going to use that class to style the menu.

First, we need to make the entire menu fluid by giving them 100% width. Also, we'll switch from a horizontal menu to a vertical one by removing the floats and we'll remove the hover displaying and effects.

#cssmenu.small-screen {
  width: 100%;
}

#cssmenu.small-screen ul {
  width: 100%;
  display: none;
}

#cssmenu.small-screen ul li {
  width: 100%;
  border-top: 1px solid rgba(120, 120, 120, 0.2);
}

#cssmenu.small-screen ul ul li,
#cssmenu.small-screen li:hover>ul>li {
  height: auto;
}

#cssmenu.small-screen ul li a,
#cssmenu.small-screen ul ul li a {
  width: 100%;
  border-bottom: 0;
}

#cssmenu.small-screen>ul>li {
  float: none;
}

#cssmenu.small-screen ul ul,
#cssmenu.small-screen ul ul ul {
  position: relative;
  left: 0;
  width: 100%;
  margin: 0;
  text-align: left;
}

If you resize your window, you can't see anything at the moment, because the button which toggles the menu is hidden. We'll display and style the button in a moment, but until then we'll add some indentation for the submenu links and hide the submenu indicators.

#cssmenu.small-screen ul ul li a {
  padding-left: 25px;
}

#cssmenu.small-screen ul ul ul li a {
  padding-left: 35px;
}

#cssmenu.small-screen>ul>li.has-sub>a:after,
#cssmenu.small-screen>ul>li.has-sub>a:before,
#cssmenu.small-screen ul ul>li.has-sub>a:after,
#cssmenu.small-screen ul ul>li.has-sub>a:before {
  display: none;
}

Now let's style the menu button. We'll use the same padding and typography as the menu links:

#cssmenu.small-screen #menu-button {
  display: block;
  padding: 17px;
  color: #dddddd;
  cursor: pointer;
  font-size: 12px;
  text-transform: uppercase;
  font-weight: 700;
}

If you resize the window to be smaller than 768px or you test the menu on a mobile device, you can now open and close the menu. The submenus are still inaccessible because they will have their own toggle buttons. The menu button needs an icon and we're going to use the so-called 'burger icon'. We're going to create it using two pseudoelements. The after pseudoelement will display two horizontal lines of the icon using borders and the before pseudoelement will display the third horizontal line.

#cssmenu.small-screen #menu-button:after {
  position: absolute;
  top: 22px;
  right: 17px;
  display: block;
  height: 4px;
  width: 20px;
  border-top: 2px solid #dddddd;
  border-bottom: 2px solid #dddddd;
  content: '';
}

#cssmenu.small-screen #menu-button:before {
  position: absolute;
  top: 16px;
  right: 17px;
  display: block;
  height: 2px;
  width: 20px;
  background: #dddddd;
  content: '';
}

The menu button looks like this now:

Creating a Responsive Menu

When the menu is opened, the menu button gets a class called menu-opened. We'll use that class to change the menu icon into an 'x' symbol. We'll use the same pseudoelement, but this time we'll remove the borders of the after, using just its body, then we're going to rotate both of them to 45 degrees in opposite directions and position them to form the symbol.

#cssmenu.small-screen #menu-button.menu-opened:after {
  top: 23px;
  border: 0;
  height: 2px;
  width: 15px;
  background: #ffffff;
  -webkit-transform: rotate(45deg);
  -moz-transform: rotate(45deg);
  -ms-transform: rotate(45deg);
  -o-transform: rotate(45deg);
  transform: rotate(45deg);
}

#cssmenu.small-screen #menu-button.menu-opened:before {
  top: 23px;
  background: #ffffff;
  width: 15px;
  -webkit-transform: rotate(-45deg);
  -moz-transform: rotate(-45deg);
  -ms-transform: rotate(-45deg);
  -o-transform: rotate(-45deg);
  transform: rotate(-45deg);
}

When the menu is opened, the menu button will look like this:

Creating a Responsive Menu

The jQuery plugin adds a span element with the submenu-button class for each submenu. These will allow the submenu to be displayed/hidden when they are clicked. They are displayed on the right side of each parent link. Also, if the parent link is already a submenu link and indicates a second level submenu, the submenu button will be smaller.

#cssmenu.small-screen .submenu-button {
  position: absolute;
  z-index: 99;
  right: 0;
  top: 0;
  display: block;
  border-left: 1px solid rgba(120, 120, 120, 0.2);
  height: 46px;
  width: 46px;
  cursor: pointer;
}

#cssmenu.small-screen ul ul .submenu-button {
  height: 34px;
  width: 34px;
}

When the submenu is opened, the plugin adds a submenu-opened class to the span. We'll use it to change the background of the span:

#cssmenu.small-screen .submenu-button.submenu-opened {
  background: #262626;
}

Now we'll add icons to the submenu buttons. We're going to use the same symbol as the submenu indicator in the desktop menu version:

#cssmenu.small-screen .submenu-button:after {
  position: absolute;
  top: 22px;
  right: 19px;
  width: 8px;
  height: 2px;
  display: block;
  background: #dddddd;
  content: '';
}

#cssmenu.small-screen ul ul .submenu-button:after {
  top: 15px;
  right: 13px;
}

#cssmenu.small-screen .submenu-button.submenu-opened:after {
  background: #ffffff;
}

#cssmenu.small-screen .submenu-button:before {
  position: absolute;
  top: 19px;
  right: 22px;
  display: block;
  width: 2px;
  height: 8px;
  background: #dddddd;
  content: '';
}

#cssmenu.small-screen ul ul .submenu-button:before {
  top: 12px;
  right: 16px;
}

#cssmenu.small-screen .submenu-button.submenu-opened:before {
  display: none;
}

Creating a Responsive Menu

The menu is now complete! I hope you enjoyed the tutorial and learned some new things!