How to style WordPress Menus & Dropdowns

Posted by & filed under Beginner, Designing for WordPress, Developing for WordPress, How To's, Inter, Menus.

The WordPress menu system is great: it’s flexible and allows users to very easily customize / control the layout of their menus, including multi-tiered drop downs. If you browse any of the theme marketplaces, such as Mojo Themes, you will see a lot of themes with beautiful drop down menus, some that are even powered with pure CSS. Have you ever wandered how to do that with CSS alone? Well, that’s what I’m going to show you.

This tutorial isn’t going to cover how to create a beautiful menu, but rather how to create the base CSS code that you will need in order to make one that is beautiful, and also functional. We will be creating a pure CSS multi-level drop down menu system. One of the primary goals is too also write our CSS such that it works with the default WordPress pages menu (displayed when a user hasn’t created a menu yet) and also the 3.0 nav menus. This way the user has a flawless experience when they activate the theme.

So I’m going to show you how to write the CSS structure needed to make something like this (just the menu):

Setting Up Our Menu and its Container

The first thing we need to do is setup our menu so that we can target it with our CSS regardless of whether a nav menu is shown or a default pages menu is displayed. To do this, we wrap our wp_nav_menu() function with a DIV that has an ID of main-nav. Note, the ID can be whatever you want, but I will use “#main-nav” throughout this tutorial.

<div id="main-nav">
	<?php wp_nav_menu(array('theme_location' => 'main_nav', 'container' => '')); ?>
</div>

I’ve set the “container” parameter to be empty because I do not want the nav menu creating a DIV, or any other kind of wrapper, for me.

When rendered, the default page menu structure looks like this:

<div class="menu">
	<ul>
		<li><a href="#">Menu Item</a></li>
		<li><a href="#">Menu Item</a>
			<ul>
				<li><a href="#">Sub Menu Item</a></li>
				<li><a href="#">Sub Menu Item</a>
					<ul>
						<li><a href="#">Sub Sub Menu Item</a></li>
						<li><a href="#">Sub Sub Menu Item</a>

						</li>
					</ul>
				</li>
			</ul>
		</li>
		<li><a href="#">Menu Item</a></li>
	</ul>
</div>

And when the 3.0 nav menu is rendered, it looks like this:

<ul>
	<li><a href="#">Menu Item</a></li>
	<li><a href="#">Menu Item</a>
		<ul>
			<li><a href="#">Sub Menu Item</a></li>
			<li><a href="#">Sub Menu Item</a>
				<ul>
					<li><a href="#">Sub Sub Menu Item</a></li>
					<li><a href="#">Sub Sub Menu Item</a>

					</li>
				</ul>
			</li>
		</ul>
	</li>
	<li><a href="#">Menu Item</a></li>
</ul>

Notice the lack of the div.menu container around the 3.0 nav menu. This is why we wrap the wp_nav_menu() function in our div#main-nav. Now this is not entirely necessary because we could simply specify a container element for the wp_nav_menu(), but it’s easier to do this and provides a bit more control when it comes to styling the menu. Now let’s start the CSS.

The Basic Menu CSS

The first thing we want to do with our CSS is setup the top level menu structure; we will do the sub menus in a moment. One of the things you should take careful note of is that I am using very general selectors. It would technically be more efficient to target the menu items with class names, but as I’m trying to ensure that my CSS works for both the default pages menu and the wp_nav_menu(), I need to use the general HTML selectors.

#main-nav	{
	height: 30px; /* set to the height you want your menu to be */
	margin: 0 0 10px; /* just to give some spacing */
}
#main-nav ul	{
	margin: 0; padding: 0; /* only needed if you have not done a CSS reset */
}
#main-nav li	{
	display: block;
	float: left;
	line-height: 30px; /* this should be the same as your #main-nav height */
	height: 30px; /* this should be the same as your #main-nav height */
	margin: 0; padding: 0; /* only needed if you don't have a reset */
	position: relative; /* this is needed in order to position sub menus */
}
#main-nav li a	{
	display: block;
	height: 30px;
	line-height: 30px;
	padding: 0 15px;
}
#main-nav .current-menu-item a, #main-nav .current_page_item a, #main-nav a:hover {
	color: #000;
	background: #ccc;
}

This CSS will setup your top level menu items in a horizontal row with each of the links being a clickable “block”, meaning that you can click on the space around the link, not just the text, essentially making the links buttons, not just text links. Also notice in the last section that I have used both “.current-menu-item” and “.current_page_item”; this is because the default pages menu and the wp_nav_menu() function assign different class names when the currently viewed page/item is displayed. I’ve also included the link hover in the list of selectors in the last section. This is because I want the link hover to match the “current page” status style.

After you’ve added some of your own design styles, your menu might look something like this:

It’s now time to get into styling the first level of sub menus. The second level (and any level past that) will be very similar to this first sub menu level, but with a couple of slight differences.

#main-nav ul ul { /* this targets all sub menus */
	display: none; /* hide all sub menus from view */
	position: absolute;
	top: 30px; /* this should be the same height as the top level menu -- height + padding + borders */
}
#main-nav ul ul li { /* this targets all submenu items */
	float: none; /* overwriting our float up above */
	width: 150px; /* set to the width you want your sub menus to be. This needs to match the value we set below */
}
#main-nav ul ul li a { /* target all sub menu item links */
	padding: 5px 10px; /* give our sub menu links a nice button feel */
}

That’s it for the basic sub menu styling, though notice that we have not yet done anything to show the sub menus when we hover over a parent. To do that, we have to use a :hover pseudo class, like so:

#main-nav ul li:hover > ul {
	display: block; /* show sub menus when hovering over a parent */
}

First, notice that I have put the :hover on the LI and not the A tag, this is because the UL is a child of the LI tag, and not the anchor link, and CSS does not have a method for selecting sibling elements. Second, take note of the fact that I use “>” immediately after the :hover pseudo class. This is because I only want to select the sub menu immediately after my menu item, not any second or third level menus we may have.

Once again, after some you have done some design CSS, your menus can now look / function like this (note the drop down):

Okay, that’s it for the first level of sub menus, and now it’s time to add a couple more styles to take care of any second and third level sub menus.

#main-nav ul ul li ul {
	/* target all second, third, and deeper level sub menus */
	left: 150px; /* this needs to match the sub menu width set above -- width + padding + borders */
	top: 0; /* this ensures the sub menu starts in line with its parent item */
}

We’re done. We now have a complete menu system with drop downs written entirely in CSS. No jQuery.

And finally, your menus could now look like this, once you have added your design CSS:

One of the great things about a CSS structure like this is that it works perfectly even when you enable jQuery animations on it, without the need for any separate styles. The only thing that is left to do from here is beautifying your menu. Add some nice borders, background colors or gradients, and maybe even some CSS3 hover transitions.

Tags: , , ,

pippin

Pippin Williamson is a WordPress developer based in Lawrence, KS. He loves writing WordPress plugins and runs a WordPress plugin-dedicated site at Pippin's Plugins.com

81 Responses

  1. Marco February 19, 2012 at 11:37 pm

    I am using the WordPress theme Socialite. I have a problem: the child pages do not show when hovering over the parent page in the menu. Please take a look: http://www.eaglefustar.com

    Maybe there is something wrong with the Socialite: Stylesheet (style.css). Please take a look:

    /***** Main Menu *****/
    #main-menu-nav{float:right;margin:30px 0;z-index:2 !important;position:relative;width:700px;}
    .home-header #main-menu-nav{margin-bottom:0 !important;}
    #main-menu ul{position:absolute;top:-999em;width:230px;}
    #main-menu ul li{width:100%;}
    #main-menu li:hover{visibility:inherit;}
    #main-menu li{float:left;position:relative;}
    #main-menu a{display:block;position:relative;}
    #main-menu li:hover ul,#main-menu li.sfHover ul{left:0;top:50px;z-index:99;}
    ul#main-menu li:hover li ul,ul#main-menu li.sfHover li ul{top:-999em;}
    ul#main-menu li li:hover ul,ul#main-menu li li.sfHover ul{left:232px;top:0;}
    ul#main-menu li li:hover li ul,ul#main-menu li li.sfHover li ul{top:-999em;}
    ul#main-menu li li li:hover ul,ul#main-menu li li li.sfHover ul{left:232px;top:0;}
    #main-menu{list-style:none;margin:0;padding:0;list-style:none;float:right;position:relative;}
    #main-menu a, #main-menu a:visited{outline:none;display:block;color:#fff;cursor:pointer;}
    #main-menu a:hover{text-decoration:none;}
    #main-menu li strong{text-transform:uppercase;display:block;font-size:14px;color:#fff;}
    #main-menu li{float:left;padding:10px 27px 10px 17px;position:relative;height:30px;vertical-align:top;margin-right:2px;}
    #main-menu .sub-menu{display:none;}
    #main-menu .nav-desc:hover, #main-menu li.parent:hover .nav-desc, #main-menu li a:hover .nav-desc{color:#ffffff;}
    #main-menu li.current-menu-item .nav-desc, #main-menu li.current_page_item .nav-desc,#main-menu li.current-menu-ancestor .nav-desc, #main-menu li.current-menu-parent .nav-desc, #main-menu li.current_page_parent .nav-desc, #main-menu li.current_page_ancestor .nav-desc{color:#ffffff !important;}
    #main-menu ul a{display:block;height:1%;width:220px;}
    #main-menu ul a span{display:block;padding:7px 13px;height:1%;cursor:pointer;}
    #main-menu ul{background:url(images/main-menu-child.png) left top repeat-y;margin:0;padding:20px 0px 10px 0px;width:230px;list-style:none;}
    #main-menu ul ul, #main-menu ul ul ul{margin:0;padding:10px 0px;width:230px;list-style:none;background:url(images/main-menu-child.png) left bottom repeat-y;}
    #main-menu ul li, #main-menu ul ul li, #main-menu ul ul ul li{margin:0;float:none;position:relative;height:1% !important;background:none;padding:0px 5px;}

    Reply
    • pippin February 20, 2012 at 10:51 pm

      Right click on the page and go to the Chrome Inspector. See the little red error indicator in the bottom right? You have jQuery errors on the page, which are preventing the drop downs from loading (since you are using Superfish). You will need to fix those errors.

  2. aiao April 3, 2012 at 7:50 pm

    Great thanks for tutorial. I’ve been looking for such a tutorial for all day with no answer for my question and finally I’ve found yours

    Reply
  3. KSosz April 7, 2012 at 6:07 am

    Very nice – thanks! I do have a question… Can I use this to make the “current” menu item stay a certain color while a visitor is on that page or archive?

    Reply
    • Harry August 12, 2014 at 1:01 am

      I have exact the same situation, when on a certain page the button hovers back to the color it started with, i want it to remain green ( in this case ) while being on that page, is there a solution for this? Sorry for my amateur English, not main language

  4. Nauman May 6, 2012 at 10:30 am

    Thanks for this tut.
    just a little tip .. if you want to active parent link while dropdown use following code:

    #main-nav li:hover > a{ color:#ccc;}

    Reply
  5. Monica May 16, 2012 at 11:14 pm

    Thanks for this tut Pippin! I’ve been fighting with my menu for 2 days and was getting pretty frustrated. I chucked my style and just built off yours, thanks again!!!!!!

    Reply
  6. Karlo August 4, 2012 at 9:16 am

    Great tutorial! Helped me alot!

    I’m only wondering whether it’s possible to make the width of the submenu block variable? Now it has a fixed width, but not all my submenu items have the same width.

    Reply
  7. Ramses August 6, 2012 at 5:07 pm

    Thanks for this, question though:

    How do I add tell wordpress to add in a mark ( like a raquo » ) after the menu title when its a dropdown list.

    And no mark, when its not a dropdown list.

    Thanks!

    Reply
  8. Mark September 1, 2012 at 6:40 pm

    Hi, Nice tutorial.

    I am using it on a project now, only problem is that the drop down menus have a fixed width and this looks messy. Is there any way to make the dropdown menus have an automatic width?

    Thanks

    Reply
  9. Monica September 4, 2012 at 9:25 pm

    Hey Pippin! I hate to bug you… but…

    I’m using this for a theme in dev and it works perfectly except when a parent link is highlighted (because it’s the current page) all the links on the corresponding submenu are too.

    When a link on a sub menu is highlighted (because it’s the current page) the parent link isn’t. Which is perfect… any thoughts?

    ^ ^ I hope that makes sense… LOL

    Reply
  10. domo December 1, 2012 at 9:05 pm

    Hi Pipin thanks for this great tutorial (please write more:))

    I think the

    #main-nav ul ul li a { /* target all sub menu item links */
    padding: 5px 10px; /* give our sub menu links a nice button feel */

    appears when you hover the parent of sub menu, making it a bit taller which does not look nice.maybe am missing something.

    Reply
  11. Guy May 7, 2013 at 5:59 pm

    Excellent. I’d been trying to find answers about styling 3rd level and deeper menu items. Your article answered all my questions! You should have a tip jar.

    Reply
  12. Arne June 22, 2013 at 7:47 am

    hi there =)
    i tried to use this..
    first thought wow nice, but i have only the first level of subs.

    #main-nav ul ul li ul {
    /* target all second, third, and deeper level sub menus */
    left: 150px; /* this needs to match the sub menu width set above — width + padding + borders */
    top: 0; /* this ensures the sub menu starts in line with its parent item */
    }

    this part doesn’t work :(

    Reply
  13. Steve June 26, 2013 at 12:03 pm

    Hi, Your menu looks great. But your tutorial does not say where I should be puuting the code. I got stumped at the very first bit as you don’t say where to place the code.

    Please elaborate as this is just what i am looking for.

    Steve

    Reply
  14. Crowds June 28, 2013 at 7:29 pm

    This is a fantastic guide thanks so much !
    Im having a slight issue with sub-menus though.
    The code
    #main-nav ul ul li ul {
    /* target all second, third, and deeper level sub menus */
    left: 150px; /* this needs to match the sub menu width set above — width + padding + borders */
    top: 0; /* this ensures the sub menu starts in line with its parent item */
    }
    top:0; dont seem to be aligning to the parent quite as it should… its about 1 pixel out :(

    Reply
  15. SF July 4, 2013 at 2:56 am

    As Marco is doing, many of us will have to add a z-index to the dropmenus to have them visible above slideshows/banners. My drops weren’t showing until I did that.

    Thanks a lot for this, a more elegant solution than I have been using.

    Reply
  16. Bernard August 1, 2013 at 11:36 am

    Very nice tut.. except you have no references to what to do when the submenu is to long? As in this method is fine with a limited amount of submenu links. What if there are say 20, then the submenu is way to long, is there a way to split the submenu.. say columns of five? Or an arbitrary width?

    Reply
  17. vimax australia September 4, 2013 at 4:41 pm

    I believe that is among the such a lot vital info for me. And i’m happy reading your article. But want to remark on few common things, The site taste is perfect, the articles is truly nice : D. Just right task, cheers

    Reply
  18. Girl September 11, 2013 at 11:58 am

    Hi there,

    I’m working on a wordpress website with a a main menu of a few elements, one of which contains 2 submenu items. It works perfect, until I hover over the submenu to click one of the submenu items. It dissapears when I leave the main menu item I hover over. What can I do to make it stay?
    thnx!

    Reply
  19. steam shower cubicles January 6, 2014 at 4:22 am

    . I was excited enough to post a comment I do have a
    few questions for you if it’s okay. Could it be just me or does it look like like a
    few of the remarks look as if they are left by brain dead individuals?
    And, if you are posting at additional places, I would like to keep up with everything new you
    have to post. Would you make a list all of your public pages like your linkedin profile, Facebook page or twitter feed?

    Reply
  20. vigrx reviews May 5, 2014 at 7:08 am

    Hi! This post could not be written any better! Reading this post reminds me of my previous
    room mate! He always kept chatting about this. I will forward this page to
    him. Fairly certain he will have a good read. Thank you
    for sharing!

    Reply
  21. kombat June 30, 2014 at 3:10 pm

    Definitely believe that which you stated.

    Your favorite justification appeared to be on the internet the simplest thing to be aware of.
    I say to you, I certainly get annoyed while people think about
    worries that they just don’t know about. You managed to hit the
    nail upon the top as well as defined out the whole thing without having side effect , people could take a signal.

    Will likely be back to get more. Thanks

    Reply
  22. Kimberley July 6, 2014 at 9:13 pm

    I see a lot of interesting articles on your blog. You have to spend a lot of time writing, i know how to save you a lot of
    time, there is a tool that creates unique, SEO friendly posts in couple of minutes,
    just type in google – laranita’s free content source

    Reply
  23. dummy ammo for sale August 24, 2014 at 3:36 am

    You should have you can contact a fabulous computer technical assistant
    or all the manufacturer. Individuals help your company when being
    an alternative origination control route fails to allow them to prevent maternity.
    Other of those sites on the internet offer braindumps on Sun microsystems 000-N23
    experience.

    Reply
  24. Anita Quiles September 10, 2014 at 6:34 pm

    My dropdown list is too long and I would like to make it look similar to “columns” instead of them all listed from top to bottom…..where would I change the css for that?

    Thanks,

    Reply
  25. Tipsninja September 26, 2014 at 4:09 am

    Great tutorial Pippin. I was stuck with adding a custom top menu for pages in a WordPress custom theme. The top level pages were working fine but I had no clue on how to set up sub pages by controlling css. Detailed and working code snippet above. It helped me solved the problem. Official wordpress help on list pages did not help me. The css for the menu is somehow tricky to handle. I had css in my theme for only top level pages and not for the child pages (submenus). Thank you.

    Reply
  26. Lalgudianz.In October 5, 2014 at 10:56 pm

    I do think this can be being among the most important information personally. And i am contented looking through your current content. However need to declaration about handful of normal factors, The web site flavour is best, this content was in point of truth pleasant : D.. physician Superb job, regards

    Reply
  27. Vedic Maths October 8, 2014 at 6:18 am

    Amazing blog! Is your theme custom made or did you download it
    from somewhere? A design like yours with a few simple
    tweeks would really make my blog jump out. Please
    let me know where you got your design. Thank you

    Reply
  28. http://411single.net/sbcka October 22, 2014 at 8:49 am

    Playboy still has the best soft porn (no penetration) in the industry.
    The 7th annual Feminist Porn Awards Gala is on Friday, April 20, at Berkeley Church (315 Queen Street East), hosted
    by Elvira Kurt and Ryan G. As Jack Venice, Reid is known for his
    role in adult films such as “Sexual Predators 2″.

    Reply
  29. Spencer October 25, 2014 at 2:36 am

    Financial savings is predicated on a comparison of the prices on all one-room, four-night time or
    longer Flight + Lodge packages booked on the American Categorical Travel website in the course of the period studied,
    August 2012 to April 2013, to the prices of the
    identical flight and lodge components discovered on the American Specific Travel web site
    if booked individually. Ebola is upon us and Republicans have a remedy: A
    travel ban. a long time upfront as a result of information about it
    was gathered via DARPA’s secret time travel program unlocks several of the more enigmatic info within the His weekly column runs on-line every Tuesday in the
    Travel / Outside section. Acquired official-wanting travel
    test voucher on 2.21.2012.

    Reply
  30. wiko ozzy noir October 26, 2014 at 10:00 pm

    We are famous throughout the country as the one stop solution to sell
    your quality pre-owned furniture. Their educated, well trained sales team is able to answer any questions
    you may have about furniture and interior designing.
    Have fun choosing those new items of Salon Furniture and they’ll serve you well over the next few years.

    Reply

Leave a Reply

XHTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>