Horizontal Drop-Down Menu

A responsive horizontal drop-down menu inspired by the Microsoft.com menu.

Horizontal Drop-Down Menu

View demo Download source

This large horizontal drop-down menu simply shows the sub-menu when an item gets clicked. It’s inspired by the Microsoft.com drop-down menu. Some example media queries show how to adjust the menu for smaller screens.

The HTML

<nav id="cbp-hrmenu" class="cbp-hrmenu">
	<ul>
		<li>
			<a href="#">Products</a>
			<div class="cbp-hrsub">
				<div class="cbp-hrsub-inner"> 
					<div>
						<h4>Learning & Games</h4>
						<ul>
							<li><a href="#">Catch the Bullet</a></li>
							<li><a href="#">Snoopydoo</a></li>
							<!-- ... -->
						</ul>
					</div>
					<div>
						<h4>Utilities</h4>
						<ul>
							<li><a href="#">Gadget Finder</a></li>
							<li><a href="#">Green Tree Express</a></li>
							<li><a href="#">Green Tree Pro</a></li>
							<li><a href="#">Wobbler 3.0</a></li>
							<li><a href="#">Coolkid</a></li>
						</ul>
					</div>
					<div>
						<!-- ... -->
					</div>
				</div><!-- /cbp-hrsub-inner -->
			</div><!-- /cbp-hrsub -->
		</li>
		<li><!-- ... --></li>
		<li><!-- ... --></li>
		<!-- ... -->
	</ul>
</nav>

The CSS

.cbp-hrmenu {
	width: 100%;
	margin-top: 2em;
	border-bottom: 4px solid #47a3da;
}

/* general ul style */
.cbp-hrmenu ul {
	margin: 0;
	padding: 0;
	list-style-type: none;
}

/* first level ul style */
.cbp-hrmenu > ul,
.cbp-hrmenu .cbp-hrsub-inner {
	width: 90%;
	max-width: 70em;
	margin: 0 auto;
	padding: 0 1.875em;
}

.cbp-hrmenu > ul > li {
	display: inline-block;
}

.cbp-hrmenu > ul > li > a {
	font-weight: 700;
	padding: 1em 2em;
	color: #999;
	display: inline-block;
}

.cbp-hrmenu > ul > li > a:hover {
	color: #47a3da;
}

.cbp-hrmenu > ul > li.cbp-hropen a,
.cbp-hrmenu > ul > li.cbp-hropen > a:hover {
	color: #fff;
	background: #47a3da;
}

/* sub-menu */
.cbp-hrmenu .cbp-hrsub {
	display: none;
	position: absolute;
	background: #47a3da;
	width: 100%;
	left: 0;
}

.cbp-hropen .cbp-hrsub {
	display: block;
	padding-bottom: 3em;
}

.cbp-hrmenu .cbp-hrsub-inner > div {
	width: 33%;
	float: left;
	padding: 0 2em 0;
}

.cbp-hrmenu .cbp-hrsub-inner:before,
.cbp-hrmenu .cbp-hrsub-inner:after {
	content: " ";
	display: table;
}

.cbp-hrmenu .cbp-hrsub-inner:after {
	clear: both;
}

.cbp-hrmenu .cbp-hrsub-inner > div a {
	line-height: 2em;
}

.cbp-hrsub h4 {
	color: #afdefa;
	padding: 2em 0 0.6em;
	margin: 0;
	font-size: 160%;
	font-weight: 300;
}

/* Examples for media queries */

@media screen and (max-width: 52.75em) { 

	.cbp-hrmenu {
		font-size: 80%;
	}

}

@media screen and (max-width: 43em) { 

	.cbp-hrmenu {
		font-size: 120%;
		border: none;
	}

	.cbp-hrmenu > ul,
	.cbp-hrmenu .cbp-hrsub-inner {
		width: 100%;
		padding: 0;
	}

	.cbp-hrmenu .cbp-hrsub-inner {
		padding: 0 2em;
		font-size: 75%;
	}

	.cbp-hrmenu > ul > li {
		display: block;
		border-bottom: 4px solid #47a3da;
	}

	.cbp-hrmenu > ul > li > a { 
		display: block;
		padding: 1em 3em;
	}

	.cbp-hrmenu .cbp-hrsub { 
		position: relative;
	}

	.cbp-hrsub h4 {
		padding-top: 0.6em;
	}

}

@media screen and (max-width: 36em) { 
	.cbp-hrmenu .cbp-hrsub-inner > div {
		width: 100%;
		float: none;
		padding: 0 2em;
	}
}

The JavaScript

var cbpHorizontalMenu = (function() {

	var $listItems = $( '#cbp-hrmenu > ul > li' ),
		$menuItems = $listItems.children( 'a' ),
		$body = $( 'body' ),
		current = -1;

	function init() {
		$menuItems.on( 'click', open );
		$listItems.on( 'click', function( event ) { event.stopPropagation(); } );
	}

	function open( event ) {

		if( current !== -1 ) {
			$listItems.eq( current ).removeClass( 'cbp-hropen' );
		}

		var $item = $( event.currentTarget ).parent( 'li' ),
			idx = $item.index();

		if( current === idx ) {
			$item.removeClass( 'cbp-hropen' );
			current = -1;
		}
		else {
			$item.addClass( 'cbp-hropen' );
			current = idx;
			$body.off( 'click' ).on( 'click', close );
		}

		return false;

	}

	function close( event ) {
		$listItems.eq( current ).removeClass( 'cbp-hropen' );
		current = -1;
	}

	return { init : init };

})();

View demo Download source

Previous:
Next:

Tagged with:

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.

View all contributions by

Website: http://www.codrops.com

Related Articles

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 111

Comments are closed.
  1. 1

    Hi,
    This is beautiful. Has anyone figured out how to keep top menu highlighted when child elements are hovered on?
    Thank you,

  2. 2

    Hey..

    I was just wondering.. How can I edit this in order to make it close when an element of the drop menu is clicked?

    Is this possible?

    Thanks in advance.

    • 3

      Well I think I fixed it but im using the menu is two locations of the same page.. It works for one but the other one doesnt seem to be affected how ever I try and change the code.

      What I did,
      $mylistItems = $( ‘.cbp-hrsub-inner > ul li’ ),
      $mymenuItems = $mylistItems.children( ‘a’ ),

      Added the above code at the start so I can focus on the items that are been clicked and then gave an click event for them. $mymenuItems.on(‘click’ , close);

      I tried changing the elements around because I had an extra div in my second instance of the menu. This didnt actually help though.


      Month

      tag

    • 6

      Well I cant actually post my code. Just realized I cant delete any of those posts also .. sigh ..

  3. 7

    Hi,

    when you set an z-index to .cbp-hrmenu .cbp-hrsub you will not have problems with absolute positioned elements on your side.

  4. 8

    This is a great tutorial but I feel like the mock up is far too complicated for trying to teach a dog new tricks- would love to see this simplified into a more simple drop down for the sake of learning.

  5. 9

    This is great — does all that I want but… I have some top-level menu items that do not have sub menus. How can I get those links to ignore the js and go directly to the url link?

    • 10

      Change the $listItems selector in the JS to only attach the menu code to those with submenus. This should work:
      $listItems = $( '#cbp-hrmenu > ul > li' ).has('ul')

    • 11

      Actually, it would probably be better to use:
      $listItems = $( '#cbp-hrmenu > ul > li' ).has( '.cbp-hrsub' )

      That way, you can have a submenu that doesn’t have a ul in it.

    • 12

      Thankyou Sunny!
      This worked great, but now my styling is gone. Is that something that should be done in the js or the css.
      I’m trying to get the parent tabs to stay highlighted when a child page is active. I don’t know if this is something that worked initially and I broke it or it’s not coded in. Does this make sense to anyone?

  6. 13

    Would there be anyway this could be used with WordPress? I would love to add this to a WordPress site.

    Thanks!

  7. 14

    Hi,

    I see a few people on here are wondering how to create the menu but have some of the top level menu items that don’t have drop down content as normal menu links that would take you away from the page.

    Has anyone discovered how to do this yet? I was trying to follow Evin’s example in the comments but this was not working for me.

    Any help would be greatly appreciated!

    Thanks in advance.

    • 15

      Hi Ronan,

      This could be done easily:

      In the JS, change $menuItems = $listItems.children( 'a' ), to $menuItems = $listItems.children( 'a.dropdown' ),

      In the HTML, change MyHyperLink to MyHyperLink wherever you need a dropdown

      This will fix your issue and make nav items without subitems clickable and take you to the new page

      Regards,
      Steven

    • 16

      Format gone, sorry for that!

      Just do as described for the JS part

      In the HTML, change a href to a class="dropdown" href wherever you have subitems and need a dropdown.

      Regards,
      Steven

    • 17

      Hi StevenCM,

      Thank you very much for that, apologies I am a beginner with JS, it worked perfectly!!

      Thanks again!

  8. 18

    Hello! I would like to put a fade in effect when click, how can I do this?

  9. 19

    I have litlle code that does same.

    $( ‘#cbp-hrmenu > ul > li’ ).click(function(){
    $( ‘#cbp-hrmenu > ul > li’ ).removeClass( ‘cbp-hropen’ );
    $(this).addClass(‘cbp-hropen’);
    });

  10. 21

    I try with this code and works good, but…:

    $(function() {
    var $oe_menu = $('#cbp-hrmenu');
    var $oe_menu_items = $oe_menu.children('li');
    var $oe_overlay = $('#oe_overlay');

    $oe_menu_items.bind('mouseenter',function(){
    var $this = $(this);
    $this.addClass('slided selected');
    $this.children('div').css('z-index','9999').stop(true,true).slideDown(200,function(){
    $oe_menu_items.not('.slided').children('div').hide();
    $this.removeClass('slided');
    });
    }).bind('mouseleave',function(){
    var $this = $(this);
    $this.removeClass('selected').children('div').css('z-index','1');
    });

    $oe_menu.bind('mouseenter',function(){
    var $this = $(this);
    $oe_overlay.stop(true,true).fadeTo(200, 0.6);
    $this.addClass('hovered');
    }).bind('mouseleave',function(){
    var $this = $(this);
    $this.removeClass('hovered');
    $oe_overlay.stop(true,true).fadeTo(200, 0);
    $oe_menu_items.children('div').hide();
    })
    });

    CSS:

    .oe_overlay{
    background:#000;
    opacity:0;
    position:fixed;
    top:0px;
    left:0px;
    width:100%;
    height:100%;
    }

    … it’s ok for desktop browser, but with touch screen (table, smartphone), not works… the dark background overlay remain open when close the panel.

    Any tips/suggestions?

  11. 28

    Note that the code to close the menu on a body click is destructive. If you have any other click events on the body, this code will break those other events.

    By name spacing the click events on the body, this can be avoided.

    Offending code: $body.off( 'click' ).on( 'click', close );

    Fixed code: $body.off( 'click.cbphr' ).on( 'click.cbphr', close );

  12. 29

    To make this menu show and hide on hover. Give each #cbp-hrmenu > ul > li a unique id and then do the following jquery –

    <script>
    var $listItems = $( '#cbp-hrmenu > ul > li' );
    $listItems.hover(function() {
    var id = $(this).attr('id');
    var t = setTimeout(function(){
    $('#'+id).addClass( 'cbp-hropen' );
    }, 200);
    }, function() {
    var id = $(this).attr('id');
    var t = setTimeout(function(){
    $('#'+id).removeClass( 'cbp-hropen' );
    }, 300);
    });
    <script>

  13. 31

    Hola Mary Lou, te agradezco mucho por iluminarnos con tus desarrollos, implementare este menú en un sitio web, si gustas luego te envió el link.

    Buenas Noches!

  14. 32

    This is a very neat drop-down menu, just one thing is essential
    if there is a main menu item with no children it will need to be a link to some page

    I recommend changing the code when defining the variables to only contain those with nested unordered lists like this

    var $listItems = $( ‘#cbp-hrmenu > ul > li’ ).has(‘ul’),

    Best

  15. 33

    Mary Lou,
    Kudos on the beautiful click and stick menu! I love it.
    I would love to get it to work on my site. I’m having some difficulty with the active tab maintaining the blue background. The input for the zindex and how to get the parent without a child to work as a link, etc. was so helpful … thank you guys! I’m a newbie to query. So I’m wondering if there is a tutorial out there that walks through the code. Or a demo with more than just the index page since I can’t look at the code and know if the link is supposed to remain active or if it’s something I broke in the process of augmenting it. Or if someone that got it to work would post a link to their site? I would be most grateful. Thank you <3

Comments are closed.