Our goal is to build a “three line” or “3 line” (☰) menu for a responsive website. We want to do this without adding additional markup to the page. Any additional markup we want to include must be added dynamically. We’re going to use jQuery to help us out.

Initial State

So here is our, initial state.

<!DOCTYPE html>
<html>
<head>
	<title>Responsive 3-Line Menu</title>
	<style type="text/css">
	* {
		margin: 0;
		padding: 0;
	}
	ul {
		width:100%;
	}

	li {
		width:33%;
		float:left;
		border-right: 1px solid #eee;
	}
	li:last-child {
		border-right:none;
	}

	li a {
		display: block;
		width:80%;
		background:#ddd;
		padding:4% 10%;
		font-size:1.35em;
		text-decoration: none;
	}

	@media screen and (max-width: 768px) {
		#menu {
			width:1.4em;
			display: block;
			background:#ddd;
			font-size:1.35em;
			text-align: center;
		}
		#nav.js {
			display: none;
		}
		ul {
			width:100%;
			list-style:none;
		}
		li {
			width:100%;
			border-right:none;
		}
	}

	@media screen and (min-width: 768px) {
		#menu {
			display: none;
		}
	}
	</style>
</head>
<body>
<ul id="nav">
	<li><a href="#">Home</a></li>
	<li><a href="#">About</a></li>
	<li><a href="#">Contact</a></li>
</ul>
</body>
</html>

We have a navigation unordered list with the id of nav. Each menu item is floated left when the browser’s viewport is larger than 768 pixels, any smaller they jump under each other.

Our aim is to hide them when we get to 768 and show a menu (☰). When you tap on the menu it reveals the navigation and once you tap again it hides it.

Getting Started

First we want to hide our navigation unordered list (#nav). In our CSS we’re doing display:none on our #nav.js. We can do this in jQuery in the following way.

$("#nav").addClass("js");

So if JavaScript is enabled it now hides. When we shrink our viewport.

Next we want to add the menu link before our #nav.

$("#nav").addClass("js").before('<div id="menu">☰</div>');

Because we have the CSS already set up to show and hide the ☰ menu we don’t have to do anything here. Next we need to add a click listener to the menu and then toggle the visibility of the #nav element.

$("#menu").click(function(){
	$("#nav").toggle();
});

Finally, if you show and hide the navigation in a small viewport and then expand the viewport again the navigation is always hidden. This is because the toggle method adds a style attribute to the navigation element. To fix this we by removing the style attribute using the removeAttr method. We need to call this when the window resizes and the width is greater than 768 pixels.

$(window).resize(function(){
	if(window.innerWidth > 768) {
		$("#nav").removeAttr("style");
	}
});

And that’s it. In a relatively short amount of code you’ve progressively enhanced a responsive site to have a “three line” menu.

Update: The code can be found on GitHub here.