Horizontal Slide Out Menu

A horizontal slide out menu with a grid-like thumbnail layout for the submenu. With media query examples for smaller devices.

HorizontalSlideOutMenu

View demo Download source

A simple, horizontal slide out menu with a grid-like thumbnail layout for the submenu. The menu slides out from the top when a main menu item is clicked and the sub-items fade in. When clicking on another item, the height of the submenu will adjust and the content will fade in and out while switching.

Some media query examples show how to make the menu responsive and change the view to a touch-friendly vertically stacked navigation.

The HTML

<nav class="cbp-hsmenu-wrapper" id="cbp-hsmenu-wrapper">
	<div class="cbp-hsinner">
		<ul class="cbp-hsmenu">
			<li>
				<a href="#">Lovely Spirits</a>
				<ul class="cbp-hssubmenu">
					<li><a href="#"><img src="images/1.png" alt="img01"/><span>Delicate Wine</span></a></li>
					<li><a href="#"><img src="images/2.png" alt="img02"/><span>Fine Spirit</span></a></li>
					<li><a href="#"><img src="images/3.png" alt="img03"/><span>Heavenly Ale</span></a></li>
					<li><a href="#"><img src="images/4.png" alt="img04"/><span>Juicy Lemonade</span></a></li>
					<li><a href="#"><img src="images/5.png" alt="img05"/><span>Wise Whiskey</span></a></li>
					<li><a href="#"><img src="images/6.png" alt="img06"/><span>Sweet Rum</span></a></li>
				</ul>
			</li>
			<li>
				<a href="#">Delicious Beverages</a>
				<ul class="cbp-hssubmenu cbp-hssub-rows">
					<li><a href="#"><img src="images/7.png" alt="img07"/><span>Lovely Slurp</span></a></li>
					<li><a href="#"><img src="images/8.png" alt="img08"/><span>Lemony Grappa</span></a></li>
					<li><a href="#"><img src="images/9.png" alt="img09"/><span>Eggy Liquor</span></a></li>
					<li><a href="#"><img src="images/10.png" alt="img10"/><span>Fresh Juice</span></a></li>
					<li><a href="#"><img src="images/1.png" alt="img01"/><span>Delicate Wine</span></a></li>
					<li><a href="#"><img src="images/2.png" alt="img02"/><span>Fine Spirit</span></a></li>
					<li><a href="#"><img src="images/3.png" alt="img03"/><span>Heavenly Ale</span></a></li>
					<li><a href="#"><img src="images/4.png" alt="img04"/><span>Juicy Lemonade</span></a></li>
					<li><a href="#"><img src="images/5.png" alt="img05"/><span>Wise Whiskey</span></a></li>
					<li><a href="#"><img src="images/6.png" alt="img06"/><span>Sweet Rum</span></a></li>
					<li><a href="#"><img src="images/1.png" alt="img01"/><span>Delicate Wine</span></a></li>
					<li><a href="#"><img src="images/2.png" alt="img02"/><span>Fine Spirit</span></a></li>
				</ul>
			</li>
			<li>
				<a href="#">Fine Liquors</a>
				<ul class="cbp-hssubmenu">
					<li><a href="#"><img src="images/10.png" alt="img10"/><span>Fresh Juice</span></a></li>
					<li><a href="#"><img src="images/6.png" alt="img06"/><span>Sweet Rum</span></a></li>
					<li><a href="#"><img src="images/9.png" alt="img09"/><span>Eggy Liquor</span></a></li>
				</ul>
			</li>
			<li><a href="#">Our Mission</a></li>
			<li><a href="#">Contact</a></li>
		</ul>
	</div>
</nav>

The CSS

@font-face {
	font-family: 'bpmenu';
	src:url('../fonts/bpmenu/bpmenu.eot');
	src:url('../fonts/bpmenu/bpmenu.eot?#iefix') format('embedded-opentype'),
		url('../fonts/bpmenu/bpmenu.woff') format('woff'),
		url('../fonts/bpmenu/bpmenu.ttf') format('truetype'),
		url('../fonts/bpmenu/bpmenu.svg#bpmenu') format('svg');
	font-weight: normal;
	font-style: normal;
}

/* Main menu wrapper */
.cbp-hsmenu-wrapper {
	position: relative;
}

/* Common style for all lists */
.cbp-hsmenu-wrapper ul {
	list-style: none;
	padding: 0;
	margin: 0 auto;
}

/* 100% width bar for menu */
.cbp-hsinner {
	background: #47a3da;
	position: relative;
	z-index: 100;
}

/* Main menu style */
.cbp-hsmenu-wrapper .cbp-hsmenu {
	width: 90%;
	max-width: 69em;
	margin: 0 auto;
	padding: 0 1.875em;
}

.cbp-hsmenu > li {
	margin-left: 4em;
	display: inline-block;
}

.cbp-hsmenu > li:first-child {
	margin-left: 0;
}

/* Main menu link style */
.cbp-hsmenu > li > a {
	color: #fff;
	font-size: 1.2em;
	line-height: 3em;
	display: inline-block;
	position: relative;
	z-index: 10000;
	outline: none;
}

.no-touch .cbp-hsmenu > li > a:hover,
.no-touch .cbp-hsmenu > li > a:focus,
.cbp-hsmenu > li.cbp-hsitem-open > a {
	color: #02639d;
}

/* Add an arrow to the main menu link if it has a submenu (not the only child) */
.cbp-hsmenu > li > a:not(:only-child):before {
	display: inline-block;
	font-family: 'bpmenu';
	speak: none;
	font-style: normal;
	font-weight: normal;
	font-variant: normal;
	text-transform: none;
	line-height: 1;
	-webkit-font-smoothing: antialiased;
	content: "\f107";
	font-size: 80%;
	margin-right: 0.3em;
	opacity: 0.4;
	vertical-align: middle;
}

.cbp-hsmenu > li.cbp-hsitem-open > a:not(:only-child):before {
	content: "\f106";
}

/* Add a triangle to currently open menu item link */
.cbp-hsmenu > li.cbp-hsitem-open > a:after {
	top: 100%;
	border: solid transparent;
	content: " ";
	height: 0;
	width: 0;
	position: absolute;
	pointer-events: none;
	border-color: transparent;
	border-top-color: #47a3da;
	border-width: 10px;
	left: 50%;
	margin-left: -10px;
}

/* Submenu style */
.cbp-hssubmenu {
	position: absolute;
	left: 0;
	top: 100%;
	width: 100%;
	z-index: 0;
	text-align: center; /* for aligning the sub items */
	visibility: hidden;
}

.cbp-hssubmenu:before, 
.cbp-hssubmenu:after { 
	content: " "; 
	display: table; 
}
.cbp-hssubmenu:after { 
	clear: both; 
}

/* Let's allow 6 item in a row */
.cbp-hssubmenu > li {
	width: 16.2%;
	display: inline-block;
	vertical-align: top;
	box-shadow: -28px 0 0 -27px #ddd, 0 -28px 0 -27px #ddd;
	opacity: 0;
	-webkit-transition: opacity 0.1s 0s;
	-moz-transition: opacity 0.1s 0s;
	transition: opacity 0.1s 0s;
}

/* First 6 items don't have upper box shadow */
.cbp-hssubmenu > li:nth-child(-n+6) {
	box-shadow: -28px 0 0 -27px #ddd;
} 

/* Every 7th item does not have a left box shadow */
.cbp-hssubmenu > li:nth-child(6n+1) {
	box-shadow:  0 -28px 0 -27px #ddd;
}

/* The first one does not have any box shadow */
.cbp-hssubmenu > li:first-child {
	box-shadow: none;
}

.cbp-hssubmenu > li a {
	display: block;
	text-align: center;
	color: #a2a2a2;
	outline: none;
	padding: 2em 1em 1em 1em;
}

.no-touch .cbp-hssubmenu > li a:hover,
.no-touch .cbp-hssubmenu > li a:focus {
	color: #888;
}

.cbp-hssubmenu > li a img {
	border: none;
	outline: none;
	display: inline-block;
	margin: 0;
	max-width: 100%;
	-webkit-transition: opacity 0.2s;
	-moz-transition: opacity 0.2s;
	transition: opacity 0.2s;
}

.no-touch .cbp-hssubmenu > li a:hover img {
	opacity: 0.5;
}

.cbp-hssubmenu > li a span {
	display: block;
	min-height: 3em;
	margin-top: 0.4em;
}

.cbp-hsmenu > li.cbp-hsitem-open .cbp-hssubmenu {
	z-index: 1000;
	visibility: visible;
}

.cbp-hsmenu > li.cbp-hsitem-open .cbp-hssubmenu > li {
	opacity: 1;
	-webkit-transition: opacity 0.5s 0.1s;
	-moz-transition: opacity 0.5s 0.1s;
	transition: opacity 0.5s 0.1s;
}

/* Helper div for animating the background */
.cbp-hsmenubg {
	background: #f7f7f7;
	position: absolute;
	width: 100%;
	top: 100%;
	left: 0;
	z-index: 0;
	height: 0px;
}

.no-touch .cbp-hsmenubg {
	-webkit-transition: height 0.3s;
	-moz-transition: height 0.3s;
	transition: height 0.3s;
}

@media screen and (max-width: 65em){
	.cbp-hsmenu-wrapper {
		font-size: 80%;
	}
}

@media screen and (max-width: 51.4375em){
	.cbp-hsmenu-wrapper {
		font-size: 100%;
	}

	.cbp-hsmenu-wrapper .cbp-hsmenu {
		padding: 0;
		max-width: none;
		width: 100%;
	}

	.cbp-hsmenu > li {
		border-top: 1px solid rgba(255,255,255,0.5);
		text-align: center;
		margin: 0 auto;
		display: block;
	}

	.cbp-hsmenu > li:first-child {
		border-top: none;
	}

	.cbp-hsmenu > li > a {
		display: block;
	}

	.cbp-hsmenu > li > a:not(:only-child):before {
		line-height: 1.8;
		right: 0;
		position: absolute;
		font-size: 200%;
	}

	.cbp-hsmenubg {
		display: none;
	}

	.cbp-hssubmenu {
		background: #f7f7f7;
		position: relative;
		overflow: hidden;
		height: 0;
	}

	.cbp-hsmenu > li.cbp-hsitem-open .cbp-hssubmenu {
		height: auto;
	}

	/* Let's only allow 3 item in a row now */
	.cbp-hssubmenu > li {
		width: 30%;
	}

	/* Reset box shadows for the 6 items in row case */
	.cbp-hssubmenu > li:nth-child(-n+6),
	.cbp-hssubmenu > li:nth-child(6n+1) {
		box-shadow: -28px 0 0 -27px #ddd, 0 -28px 0 -27px #ddd;
	}

	/* First 4 items don't have upper box shadow */
	.cbp-hssubmenu > li:nth-child(-n+3) {
		box-shadow: -28px 0 0 -27px #ddd;
	} 

	/* Every 5th item does not have a left box shadow */
	.cbp-hssubmenu > li:nth-child(3n+1) {
		box-shadow:  0 -28px 0 -27px #ddd;
	}

}

@media screen and (max-width: 25em){
	/* Let's only allow 1 item in a row now */
	.cbp-hssubmenu > li {
		width: 100%;
		display: block;
	}

	.cbp-hsmenu-wrapper .cbp-hssubmenu > li {
		box-shadow: 0 1px #cecece;
		text-align: left;
	}

	.cbp-hssubmenu > li a {
		text-align: left;
		line-height: 50px;
		padding: 0.4em 1em;
	}

	.cbp-hssubmenu > li a img {
		float: left;
		max-height: 50px;
	}

	.cbp-hssubmenu > li a span {
		min-height: 0;
		margin: 0;
	}
}

The JavaScript

/**
 * cbpHorizontalSlideOutMenu.js v1.0.0
 * http://www.codrops.com
 *
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 * 
 * Copyright 2013, Codrops
 * http://www.codrops.com
 */
;( function( window ) {
	
	'use strict';

	var document = window.document;

	function extend( a, b ) {
		for( var key in b ) { 
			if( b.hasOwnProperty( key ) ) {
				a[key] = b[key];
			}
		}
		return a;
	}

	function cbpHorizontalSlideOutMenu( el, options ) {	
		this.el = el;
		this.options = extend( this.defaults, options );
		this._init();
	}

	cbpHorizontalSlideOutMenu.prototype = {
		defaults : {},
		_init : function() {
			this.current = -1;
			this.touch = Modernizr.touch;
			this.menu = this.el.querySelector( '.cbp-hsmenu' );
			this.menuItems = this.el.querySelectorAll( '.cbp-hsmenu > li' );
			this.menuBg = document.createElement( 'div' );
			this.menuBg.className = 'cbp-hsmenubg';
			this.el.appendChild( this.menuBg );
			this._initEvents();
		},
		_openMenu : function( el, ev ) {
			
			var self = this,
				item = el.parentNode,
				items = Array.prototype.slice.call( this.menuItems ),
				submenu = item.querySelector( '.cbp-hssubmenu' ),
				closeCurrent = function( current ) {
					var current = current || self.menuItems[ self.current ];
					current.className = '';
					current.setAttribute( 'data-open', '' );	
				},
				closePanel = function() {
					self.current = -1;
					self.menuBg.style.height = '0px';
				};

			if( submenu ) {

				ev.preventDefault();

				if( item.getAttribute( 'data-open' ) === 'open' ) {
					closeCurrent( item );
					closePanel();
				}
				else {
					item.setAttribute( 'data-open', 'open' );
					if( self.current !== -1 ) {
						closeCurrent();
					}
					self.current = items.indexOf( item );
					item.className = 'cbp-hsitem-open';
					self.menuBg.style.height = submenu.offsetHeight + 'px';
				}
			}
			else {
				if( self.current !== -1 ) {
					closeCurrent();
					closePanel();
				}
			}

		},
		_initEvents : function() {
			
			var self = this;

			Array.prototype.slice.call( this.menuItems ).forEach( function( el, i ) {
				var trigger = el.querySelector( 'a' );
				if( self.touch ) {
					trigger.addEventListener( 'touchstart', function( ev ) { self._openMenu( this, ev ); } );
				}
				else {
					trigger.addEventListener( 'click', function( ev ) { self._openMenu( this, ev ); } );	
				}
			} );
			
			window.addEventListener( 'resize', function( ev ) { self._resizeHandler(); } );

		},
		// taken from https://github.com/desandro/vanilla-masonry/blob/master/masonry.js by David DeSandro
		// original debounce by John Hann
    	// http://unscriptable.com/index.php/2009/03/20/debouncing-javascript-methods/
		_resizeHandler : function() {
			var self = this;
			function delayed() {
				self._resize();
				self._resizeTimeout = null;
			}

			if ( this._resizeTimeout ) {
				clearTimeout( this._resizeTimeout );
			}

			this._resizeTimeout = setTimeout( delayed, 50 );
		},
		_resize : function() {
			if( this.current !== -1 ) {
				this.menuBg.style.height = this.menuItems[ this.current ].querySelector( '.cbp-hssubmenu' ).offsetHeight + 'px';
			}
		}
	}

	// add to global namespace
	window.cbpHorizontalSlideOutMenu = cbpHorizontalSlideOutMenu;

} )( window );

View demo Download source

Previous:
Next:

Tagged with:

Mary Lou (Manoela Ilic) 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://tympanus.net/

Related Articles

Feedback 66

  1. 1

    Hi,

    Menu is not collected when pulled out of the mouse.

    Mouse is clicked on the link in the menu will grow back or want to get top.

    • 4

      Hello Andrew,, i put this very cool menu in my website, have a look at the HTML source code to adding other drop down category (I make 5).
      All is working well for me on all browser.
      I want to thank you “Mary Lou” for this pretty menu.

  2. 6

    Hi, menu is Great!
    But I con not add button “Close” like “X”
    may be anybody can help me?

    Menu doesn’t work on IE11 on windows8

  3. 7

    This menu is great! Is there a way to have the submenu close when clicking on a submenu link? I am using anchors on my page, so I just want the submenu to collapse when the user clicks one of the links.

  4. 8

    This slide down menu is awesome. But I am facing an issue on reducing the size of the browser. The slide out menu does not show up. Is there a solution known to anyone for this ??
    Thanks a ton

  5. 9

    Hello, i have over 100 Sub Categories and the browser Window use the height from the Submenu and show me a scrollbar (The Submenu is not opened, how can i change it to show the scrollbar when i open the submenu?

  6. 12

    Hi, does anyone know how to change the ‘click’ on the main menu list item to a ‘hover’?

    Thanks

  7. 13

    Hi, does anyone know how to change the ‘click’ on the main menu list item to a ‘hover’?

    • 14

      Hi, have managed to switch to hover, but only problem being getting the menu to hide again on hover out whilst maintaining functionality is proving ellusive *puzzled*

  8. 15

    Had some issues with making another button (breadcrumb link) open the submenu as well as the main menu click..


    $('a.LINKCLASS').on('click',function(){
    var thisid=$('.MENUBUTTON_class_That_you_want_to_click').parent("li"); // added a class to the menu's <a link>
    $(thisid).attr('data-open','open');
    $(thisid).attr('class','cbp-hsitem-open');
    setTimeout( resize_submenuheight, 50 ); // important delay
    });
    function resize_submenuheight(){
    var height=$('.click_all_scents').parent("li").children('.cbp-hssubmenu').outerHeight();
    $(".cbp-hsmenubg").css("height",height+'px');
    }

  9. 16

    Hello !

    want to know if it’s possible to close the menu when we click somewhere on the page. i’m not that good with javascript, so if i can get some help, it will be great :)

    • 17

      Hi all,

      I’d love to know this too. If someone could help out, it would be appreciated greatly!

  10. 18

    Hi, really need to know how to open a sub menu on page load, it has been asked twice before but not answered, Thanks in advance.

Follow this discussion

Leave a Comment

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>