Vertical Sliding Menu with Jquery

by jonathan | Nov 10, 2009 at 9:00 am | Featured, tutorial, web design

VerticalMenuTitleWhen WordPress changed their administrator layout I was fascinated with the navigation menu. It has a sleek and useful feel to it. Notable features would include the active styling to your current page, the sliding action of each menu section, the hover effect that shows the user which menu can be opened and how it keeps menus open between page views. Someone who designs and codes web sites can not just look at the end user experience but also the code behind the menu. I think WordPress does a very good job of using images and css to style the menu efficiently and cleanly but enough about WordPress let me get to what this article will be about.

I want to show how a vertical sliding menu can take on some of the features WordPress has implemented but also keep it simple to explain. I did not want to use any images to style the menu and keep everything as clean as possible. What I ended up with was 50% css, 25% jquery and 25% html. I used a few advanced CSS selectors and attributes (like border radius) to refine the effect.

Take a look at the final product here and read on for the explanation. Like always I have put the CSS and jquery in the same file to make it easy for you to inspect and download.

Lets start out with the base HTML. We start with a simple list

<div id="menu">
 <ul class="navmenu">
   <li><div class="menutop"><a href="#">Posts</a><div class="toggle">+</div></div>
     <ul class="submenu">
       <li><a href="#">Add New</a></li>
       <li><a href="#">Tags</a></li>
     </ul>
   </li>
   <li><div class="menutop"><a href="#">Pages</a><div class="toggle">+</div></div>
     <ul class="submenu">
       <li><a href="#">Add New</a></li>
       <li><a href="#">Edit</a></li>
     </ul>
   </li>
   <li><div class="menutop menusingle"><a href="#">Comments</a></div></li>
   <li><div class="menutop"><a href="#">Users</a><div class="toggle">+</div></div>
     <ul class="submenu">
       <li><a href="#">Manage</a></li>
       <li><a href="#">Add New</a></li>
       <li><a href="#">Profile</a></li>
     </ul>
   </li>
 </ul>
 </div>

I start by wrapping the whole thing in a div with a class of ‘menu’. Then everything else is nested unordered lists. Let me go over the rest of the class names.

menuCss

navmenu

This is the class for the top most unordered list.

menutop

This is given a div within the line items that will be displayed as visual headers for each section. Wrapping your links inside of a div is only necessary for the heading line items.

menusingle

This is a special class applied to the heading line items that will not have a nested list.

toggle

This class is applied to a div tag which is inside the menutop div. This allows you to link the header title to a page while the toggle div is clicked to expand the list.

submenu

This is applied to the ‘ul’ tag of the nested lists.

What really makes the list look nice is the CSS.

 /*Toggle Area*/
 #menu .toggle {float:right;width:9px; padding:5px; cursor:pointer; border-top:1px solid white; border-left:1px solid #E0E0E0; color:#999;}
 #menu ul.navmenu li:first-child .toggle{border-width:0 0 0 1px;}

 /*Menu Setup*/
 #menu ul{padding:0; margin:0; width:150px;}
 #menu ul ul{border:1px solid #CCC;}
 #menu ul.navmenu li {margin:0; list-style:none;}
 /*Links*/
 #menu ul.navmenu a, #menu ul.navmenu a:visited {text-decoration:none; padding:5px; display:block; color:#008FDD;}
 #menu ul.navmenu ul.submenu a:hover{background:#FFF4D2; color:#333;}
 /*Heading Outer div*/
 #menu ul.navmenu .menutop{border:1px solid #CCC; border-width:0 1px; overflow:hidden; width:150px; background:#F9F9F9; }
 /*Header Links*/
 #menu ul.navmenu .menutop a{width:120px;float:left;margin:0 0 1px 0; border-top:1px solid white;}
 /*Header Link Hover*/
 #menu ul.navmenu .menutop a:hover{color:#333;}
 /*Removes white border for the first header*/
 #menu ul.navmenu li:first-child .menutop a {border-width:0px;}

 /*Single Menu Width Fix*/
 #menu ul.navmenu .menusingle a{width:140px;}

 /*Border Radius and Special Border Width*/
 #menu ul.navmenu li:first-child .menutop{border-width:1px 1px 0 1px; -moz-border-radius:5px 5px 0 0;-webkit-border-top-left-radius:5px;-webkit-border-top-right-radius:5px;}
 #menu ul.navmenu li:last-child .menutop{border-width:0px 1px 1px 1px; -moz-border-radius:0 0 5px 5px; -webkit-border-bottom-left-radius:5px;-webkit-border-bottom-right-radius:5px;}
 #menu ul.navmenu li:last-child ul.submenu{-moz-border-radius:0 0 5px 5px;-webkit-border-bottom-left-radius:5px;-webkit-border-bottom-right-radius:5px;}
 #menu ul.navmenu li:last-child .menutop-open{-moz-border-radius:0;-webkit-border-radius:0px; border-width:0 1px;}

Lets break it down. There is a lot here so I am only going to hit on each area.

Toggle Area
This sets up the styling for the area with the “+” and “-“. Because this is floated to the right of the heading div it needs a width and it will be used as a click-able area so I added the pointer when you roll over it. The line that uses li:first-child only selects the first line item within the ul.navmneu selection. That this way I can remove the white top border for the very first header
Menu Setup

This is the basic stuff to reset the margin, padding and to set the list style to none. I also add a border around the nested lists so that they create some separation when opened.

Links

Nothing to special here. I make sure to apply all the padding that I want for each line to the link tag. That way when I apply a hover style I can change the background color and the whole line will change.padding

Heading Outer Div

In order to get the appropriate border around the menu I decided to let each heading area have a border and then the nested list get their own border. This area not only applies the border to just the sides of the heading div but also sets it’s width and overflow. The overflow is important because the items within the div will be floated so the height will not be calculated correctly without the overflow setting.HeaderArea

Heading Links

This area sets up the links within the heading section. The width is set because the item is floated. Remember to add in your padding and border widths when figuring your widths.

Single Menu

I wanted to show the flexibility of coding for different situations. I made sure to take into account if a menu heading will not have any sub links. This sets the width correctly thinking that the toggle area will be removed.

Border Widths and Radius

This area has a lot of extra code for the rounded borders that look nice in Firefox and Webkit. However it also creates the top and bottom border that completes the border around the whole menu. I am using :first-child and :last-child to select the top and bottom header items. As a special note none of the border radius styles will work in IE, which is no big deal. However the :last-child also is not followed by IE but I have a fix for that in the java code.

I tried to create something that was usable out of the box but still very simple. If you are having trouble understanding the CSS I recommend getting Firebug for Firefox and using that to see what CSS is effecting what area.

For the javascript I am using the Jquery library and it looks like this.

if ($.browser.msie){
   $('#menu ul.navmenu li:last-child .menutop').css('border-width','0 1px 1px;')
 }

 $('.toggle:not(.toggle-open)') .addClass('toggle-closed') .parents('li') .children('ul') .hide();    

 $('.toggle') .click(function(){
   if ($(this) .hasClass('toggle-open')) {
     $(this) .removeClass('toggle-open') .addClass('toggle-closed') .empty('') .append('+') .parents('li') .children('ul') .slideUp(250);
     $(this) .parent('.menutop') .removeClass('menutop-open') .addClass('menutop-closed');
   }else{
     $(this) .parent('.menutop') .removeClass('menutop-closed') .addClass('menutop-open');
     $(this) .removeClass('toggle-closed') .addClass('toggle-open') .empty('') .append('&ndash;') .parents('li') .children('ul') .slideDown(250);
 }
 })

This all within the normal doc.ready function that starts up the Jquery code. I first start out with a simple fix for IE not following the :last-child selector. I thought if IE does not support it I bet Jquery still does and this works. I check to see if the browser is IE and then apply the style as an inline element.

Before proceeding I need to explain a little about how the menu is going to work. Basically the java code will check for any toggle divs with the class of “toggle-open” and then close all the menus where the open class is not found. This is also how the java code will know if a menu is open or closed and how you can style items depending on if they are open or not.

$('.toggle:not(.toggle-open)') .addClass('toggle-closed') .parents('li') .children('ul') .hide();

This line looks for all the items with the class “toggle” and then looks to see if that item has “toggle-open” if not it finds the previous line item and then the next ul tag and hides it. We could have just hand coded in to hide all the sub menus before hand however this will allow those people without java enable to still view the contents of the menu. Also this allows you to specify if a menu is going to be open or not before the java gets to it.

The next java line is a click function that makes the sub menus slide open and closed. It starts with an if statement that looks to see if the toggle element has the class “toggle-open”, if not then it knows the menu is closed.

$(this) .removeClass('toggle-open') .addClass('toggle-closed') .empty('') .append('+') .parents('li') .children('ul') .slideUp(250);

The next line is used if the “toggle-open” class if found and the menu should be closed. “This” refers to the clicked item. So it removes the open class and adds the “toggle-closed” class. It then empties the text held within the toggle div and adds a plus sign. Then the parent line item is found and the next ul tag after that. Finally it slides up the sub menu.

The next line that adds the open or closed class to the menutop div is just for styling and I do not use it here. This would allow you to style the whole heading area for each section depending of if they are open or closed.

After the else statement the code is just the opposite. The only special thing is instead of adding a plus sign I add an “ndash”. This looks better than the minus sign but you can change this to add whatever you want or not add anything if you are using background images.

That is it. It seems like a lot of code for something so small but having a menu that is easy to use and easy on the eyes can go a long way. Please leave any questions or comments down below and thanks for reading.

Check out the final product in the demo.

In the next installment I will talk about how to set cookies in order to remember what menus are open between page views and also and easy way to create active styling for the current page.

35 responses to “Vertical Sliding Menu with Jquery”

  1. […] This post was mentioned on Twitter by Pinceladas da Web, 7ontheline. 7ontheline said: Vertical Sliding Menu with Jquery http://ff.im/-bfDuI […]

  2. Social comments and analytics for this post…

    This post was mentioned on Twitter by 7ontheline: Vertical Sliding Menu with Jquery http://ff.im/-bfDuI

  3. Nice one, here’s another similar type of menu which slides out horizontally though;
    http://ra-ajax.org/Docs.aspx?class=Ra.Extensions.Widgets.SlidingMenu

    It’s a little bit slow because it’s in a Norwegian server, but in a US server it’d be really snappy in fact … 🙂

    Still, yours is also a nice idea … 🙂

    I love the pattern of “not showing anything more than absolutely necessary”…

  4. Sriraman says:

    One out of the context question, i like the writing on the pictures. which software you used to get this done ?

  5. Jonathan says:

    Thanks for the question. The font is called Segoe Script. I am not sure if it is standard with Windows but you can download it for a price. For the graphics I used Photoshop and Illustrator.

  6. Harry says:

    Hi there, great menu just what I was looking for!
    Quick question, is there a way to get the menu to move upwards (imagine the menu is in the bottom left of a page so when the submenus are activated they push the rest of the menu up)?
    If you could help at all that would be fantastic cheers!

  7. Jonathan says:

    So after a long time of looking for an example of how to create a menu that slides up and not down I decided that it would be easier to just make one up my self. The basis is pretty much the same only there are some tricky things happening with the CSS position. I didn’t know if you wanted something that was in the bottom left of a div or in a the browser window. Anyway take a look at the example file HERE.
    If you are interested in having a write up about this please let me know.

  8. agrigndiz says:

    Kick-ass post, great looking blog, added it to my favs.

  9. Caroline says:

    Hi Jonathon,

    Thanks for a great tutorial and code, it is exactly what I had in mind and even I, having no jquery experience, has managed to get it up and running, thank you!
    I was wondering if there was anyway to keep the menu’s open after navigating to a new page?

  10. Great post, love the use of the JQuery. Did you ever post how to use cookies to remember the expanded items in the menu?

  11. Juan Farias says:

    Thanks, I really enjoyed this tutorial. I have a question. In ie6 and ie7 there seems to be white spaces that break up the border any ideas on how to get this working for those browsers?

    Thanks again.

  12. Jonathan says:

    @Juan Farias
    I just noticed that in IE7. It had to do with not floating the list items in the first unordered list. I have made two additions to the css. 1. I added float:left to #menu ul.navmenu li 2. I removed the float for the second list items by adding float:none to #menu ul.navmenu li li
    I know it fixes the look in IE7 but I am unsure what IE6 looks like.

  13. Jonathan says:

    @Caroline, @Dave Pidgeon
    I do plan on writing up something about keeping menus open between page refreshes. As a starter I use a jquery plug-in that writes information to a cookie when you click on one of the open menu buttons. Then for every page load I read that cooking and open the menus appropriately.

  14. Bregt says:

    I got the error:
    “Error: $(“.toggle:not(.toggle-open)”) is null” ?

  15. Bregt says:

    Problem solved. Excuse me!

  16. MAL says:

    Hi, I’m curious to know if there would be a possibility to be able to click on the category name and that would open it (same functionality with the +).

    Also, if you go into a sub-menu, it’d be great if the menu would stay highlighted properly.

    Would that be hard to do ?

  17. Adam says:

    I have the same question has MAL:

    “Is there a possibility to be able to click on the category name and that would open it (same functionality with the +).”

    Thanks 🙂

  18. anna says:

    Thank you very much, it works perfectly within a tab menu and that was just what I´ve been looking for all week!

  19. Mark says:

    Love the product…Are you ever going to publish additional information on how to set cookies in order to remember what menus are open, etc. as referenced in your original post?

  20. Helen says:

    Hi Jonathan,

    This is great.

    But just tested it on IE9 [on IETester] and the menu just remains open, with ‘+’ signs. Couldn’t close the menu items. Good old IE, eh…..

    Helen

  21. Jermaine says:

    Is there a way to have the menu open from start.

  22. El Kilko says:

    Nice tutorial but it does not work properly on IE

  23. Abhinav Siddharth says:

    Hi, I was wondering if its possible to have it within a table. I have gone through your accordion example for table, which solves half of my problem but now I need that toggle things should happen only when you click on first column of the table and not the entire header. Any possible solutions you have?

    Much appreciate your response. Thanks!

  24. Abhinav Siddharth says:

    solved it myself-> I declared the first column as a class (configtoggle) and used below jquery code:

    span { font-family: “Courier New”; font-size: 10pt; color: rgb(0, 0, 0); background: none repeat scroll 0% 0% rgb(255, 255, 255); }.L3S33 { color: rgb(0, 147, 0); }.L3S50 { color: rgb(0, 0, 139); }.L3S51 { color: rgb(139, 0, 0); }

        jQuery(‘th.configtoggle’).click(function() {

            jQuery(this).parents(‘table.bar’).children(‘tbody’).toggle();

            return false;

        });

        jQuery(‘th.configtoggle’).parents(‘table.bar’).children(‘tbody’).toggle();

    And again, many thanks for this tutorial 🙂
    I am an SAP CRM developer,working with jQuery to design screens and hence my first attempt to use jQuery, literally!! 🙂

     

  25. Bahrudeen A Ahamed N says:

    hi, thanks for this posting, it is really very useful for me, however can u please explain how this will work for one more sub menu, say. (topmenu–>submenu–>submenu1 etc.,), thanks 

  26. Dhaval Thakor says:

    Thanks alot .. it helps me alot

  27. Jennifer Draper says:

    Is there any chance you can show how I would be able to open a category and when I click on another one that one that i opened closes without the need to click it close,but by having it closed by picking that other one? I am using the sliderup one.

  28. […] 1. Vertical Sliding Menu with jQuery (Demo | Tutorial) […]

Leave a Reply