How to Build a CSS3 Sliding Menu

Contributing Editor

It’s often best to put things away until you need them. Navigation menus are a good example. If I’m reading an article, I don’t want a large proportion of screen real estate taken with links — especially on a mobile device.

In this article, we’re going to build a slide-out menu using CSS alone. If you’re using a modern browser, it will also show a lovely 3D page effect. This is what we’ll achieve:

View the CSS3 sliding menu demonstration…

CSS3 Sliding Menu

There are various solutions throughout the web, but I struggled to find one matching my requirements:

  1. It must use clean semantic HTML5 with no superfluous tags.
  2. It must not rely on JavaScript.
  3. It must not require additional graphics.
  4. It must work on mobile and tablet touch devices.
  5. It must degrade gracefully in older browsers (IE7+) or when specific CSS3 properties are not supported.
  6. It must look great!

Open your favorite editor and let’s get coding…

The HTML

No surprises here — we have an HTML5 document, the IE shim, a link to our stylesheet, a nav element for the menu, and an article for our body text:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>Revealing CSS3 Menu</title>
<!--[if lt IE 9]>
<script src="http://html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
<link rel="stylesheet" media="all" href="styles.css" />
</head>
<body>

	<!-- menu -->
	<nav>
		<ul>
			<li><a href="http://www.sitepoint.com/">SitePoint.com</a></li>
			<li><a href="http://www.sitepoint.com/css3-sliding-menu/">Revealing CSS3 Menu</a></li>
		</ul>
	</nav>

	<!-- main article -->
	<article>

		<h1>Revealing CSS3 Menu</h1>

		<p>body text</p>

	</article>

</body>
</html>

CSS: Article Styles

The article is a little unusual because we want to apply a 3D effect when the menu slides into place. It’s given a fixed position so it matches the dimensions of the body:

article
{
	position: fixed;
	width: 70%;
	left: 0;
	top: 0;
	right: 0;
	bottom: 0;
	padding: 30px 15%;
	background-color: #fff;
	overflow: auto;
	z-index: 0;
	-webkit-transform-origin: 0 50%;
	-moz-transform-origin: 0 50%;
	-ms-transform-origin: 0 50%;
	-o-transform-origin: 0 50%;
	transform-origin: 0 50%;
}

We’ve also defined the transform-origin to the middle of the left-hand edge. Even though the transform doesn’t occur until hover, Chrome becomes upset if we attempt to set the origin in the :hover styles.

We also require a shadow overlay when the page rotates — the right-hand edge will be darker, so we can do that with a gradient applied to a pseudo element attached to the article:

article:after
{
	position: absolute;
	content: ' ';
	left: 100%;
	top: 0;
	right: 0;
	bottom: 0;
	background-image: -webkit-linear-gradient(right, rgba(0,0,0,0.2) 0%, transparent 100%);
	background-image: -moz-linear-gradient(right, rgba(0,0,0,0.2) 0%, transparent 100%);
	background-image: -ms-linear-gradient(right, rgba(0,0,0,0.2) 0%, transparent 100%);
	background-image: -o-linear-gradient(right, rgba(0,0,0,0.2) 0%, transparent 100%);
	background-image: linear-gradient(right, rgba(0,0,0,0.2) 0%, transparent 100%);
	pointer-events: none;
}

The element is fixed as a zero-width block on the right-hand edge of the screen which is resized when the menu slides out. Note the pointer-events property — I said it would come in useful!

CSS: Navigation Styles

The main navigation block is fixed to the left of the screen. The content has a width of 16em, so we move it off to the left with -16em. However, the 50px right border will be shown. We can also apply a pseudo element to create a CSS triangle:

nav
{
	position: fixed;
	left: -16em;
	top: 0;
	bottom: 0;
	background-color: #654;
	border-right: 50px solid #765;
	box-shadow: 4px 0 5px rgba(0,0,0,0.2);
	z-index: 1;
	cursor: pointer;
}

nav:after
{
	position: absolute;
	content: ' ';
	width: 0;
	height: 0;
	right: -70px;
	top: 50%;
	border-width: 15px 10px;
	border-style: solid;
	border-color: transparent transparent transparent #765;
}

The menu styling is nothing unusual. The outer ul is given a width of 14em and padding of 1em which determines the 16em total:

nav ul
{
	width: 14em;
	list-style-type: none;
	margin: 0;
	padding: 1em;
}

CSS: The Animation

This is where it gets interesting. First, let’s apply transitions to the article, nav and menu items:

article, article:after, nav, nav *
{
	-webkit-transition: all 600ms ease;
	-moz-transition: all 600ms ease;
	-ms-transition: all 600ms ease;
	-o-transition: all 600ms ease;
	transition: all 600ms ease;
}

Moving the menu into place is simple — we move it from -16em to 0 when the user hovers over the element:

nav:hover
{
	left: 0;
}

The page effect is applied to any article sibling following the hovered nav. The translateX moves it by 16em to the right to make room for the menu. The perspective and rotateY apply a 3D transformation:

nav:hover ~ article
{
	-webkit-transform: translateX(16em) perspective(600px) rotateY(10deg);
	-moz-transform: translateX(16em) perspective(600px) rotateY(10deg);
	-ms-transform: translateX(16em) perspective(600px) rotateY(10deg);
	-o-transform: translateX(16em) perspective(600px) rotateY(10deg);
	transform: translateX(16em) perspective(600px) rotateY(10deg);
}

Finally, the shadow gradient applied to the article’s pseudo element has the left hand edge moved from 100% to 60%. In other words, it grows to 40% of the page width:

nav:hover ~ article:after
{
	left: 60%;
}

An that’s it. Even with vendor prefixes, the return on coding investment is far higher than you’d expect.

View the CSS3 sliding menu demonstration…

View the full stylesheet…

The page works in most browsers. Firefox is perfect, although:

  • The page shadow appears instantly rather than expanding over time in Chrome and Safari (webkit does not support pseudo element animation).
  • Opera does not support the 3D page transforms — the menu slides out over the page.
  • IE does not support transform so the menu covers the page. Few of the effects are shown in IE7 and 8, but the menu can be used.
  • Mobile browsers such as Android, Dolphin and Firefox Mobile work well although performance might be an issue on slower devices.

Let me know if you apply similar effects to your site.

And if you enjoyed reading this post, you’ll love Learnable; the place to learn fresh skills and techniques from the masters. Members get instant access to all of SitePoint’s ebooks and interactive online courses, like Learn CSS3.

Comments on this article are closed. Have a question about CSS3? Why not ask it on our forums?

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

  • Bato Prosic

    Hey…nice demo. Next time you make one…maybe include a link to where you really got the idea from…since it’s implemented more nicely there… http://lab.hakim.se/meny/

    I mean it’s kind of shameless to try to make it look like you came up with it all by yourself. It has been all over the Internets for the last couple of weeks…

    • http://www.optimalworks.net/ Craig Buckler

      See my comment above. The article points out that similar demos are everywhere — to my knowledge, Meny wasn’t the first and won’t be the last. It looks better, but this version uses different techniques, doesn’t require extra HTML tags, works without JS and supports IE7 and 8.

      • Michael Caldwell

        Yeah. No. Not really buying it. You say there are ‘various solutions’ and ‘similar demos everywhere’, but, fact is, I’ve only seen one before this. It was http://lab.hakim.se/meny. Yours is EXTREMELY similar to it.

        Don’t get me wrong, I think you’ve truly added value by writing up the technique. If your claimed improvements work, even better. This is one of the great things about the web dev/design community — lot’s of shared code and inspiration, folks offering suggestions and improvements, building on the foundation of previous work. A truly collegial atmosphere of respect rarely devolves into a “raging ‘my menu slider’s better than yours’ debate.”

        But, ya gotta give credit where credit is due.

      • http://www.optimalworks.net/ Craig Buckler

        How about this one:
        http://css.dzone.com/articles/css3-3d-top-shift-menu
        or even http://christianheilmann.com/

        I’m happy to give credit to anyone who came up with the idea (even if my implementation is different). Are you sure it’s Meny?

  • CSD

    The demo seems a bit buggy on iOS devices (iPhone and iPad), but worked fine on my android v2.3 phone. Could it be an issue with how the hover event is interpreted in Safari for iOS?

    • http://www.optimalworks.net/ Craig Buckler

      Of all the browsers I tried, webkit caused the most problems (even to the point of hanging Chrome during development). It’s a good lesson for anyone who thinks webkit is the only engine worth worrying about.

  • http://awhite.ca Andrew W

    Is this based on Hakim’s “Meny” that was released a few weeks ago?

    http://lab.hakim.se/meny/

    • http://awhite.ca Andrew W

      Sorry, I see that it’s something quite different; my apologies!

      • T

        No, it is literally the same thing.

    • http://www.optimalworks.net/ Craig Buckler

      No. I’ve seen the concept used in several places. If I recall correctly, the first time I saw a similar effect was on Christian Heilmann’s site several months ago.

      Forgive the pun, but Meny is one of many and they all use different techniques. Meny looks better than my example (the menu also rotates), but it requires extra tags, uses JavaScript and fails in IE8 and below.

  • Jack Baltzer

    It looks cool and all, but how can people with only keyboard navigate around on a page using this kind of navigation?

    • http://www.optimalworks.net/ Craig Buckler

      Good point. I’ll look into that.

  • Matt

    Demo looks great but a real shame that you didn’t link to a few of the examples that inspired this no-JS version. Would of given more weight to your pretty ‘clean’ solution. I can see how it’s different to Meny (which is very popular) but it wasn’t immediate obvious from a first glance (fairly clear in the text though, so long as you aren’t skim-reading!)

    Demo works great for me though and a nice, quick explanation. Making things simple isn’t easy so this is good!

    • http://www.optimalworks.net/ Craig Buckler

      Fair point, but do you keep the URLs of every nice effect you’ve seen? I don’t!

      In addition, is it good etiquette to link to other people’s hard work and point out the problems? It’d soon turn into a raging “my menu slider’s better than yours” debate. Besides, if you’re skimming the article, you wouldn’t notice those references anyway!

  • http://www.interativadesenvolvimento.com.br Diego Andrade

    Nice use of HTML5 semantics and CSS3 techniques! I like this kind of work. Even if people say this is inspired on other ideas, I must to agree that the approach is different. And the only shame I can see here is the Webkit failing to execute well the sample.

  • Alex F

    Thanks for providing a CSS only version of this technique. Great article as always!

  • http://haunschild.de Marc Haunschild

    strange thing – it works on my iPhone, but not on the iPad – both using iOS5…

    • http://www.optimalworks.net/ Craig Buckler

      Strange. I’ve heard a few people mention iPhone compatibility issues, but I thought the iPad version was much the same?

  • http://www.stickytoffee.co.uk Dennis

    Just a suggestion, but those suggesting this is just a copy of Hakim’s Meny should read the text as well as looking at the pictures. Meny isn’t the first example I’ve seen – I remember seeing a javascripted example of this years ago, secondly Meny uses javascript and doesn’t follow Craig’s guideline rules:-
    1 It must use clean semantic HTML5 with no superfluous tags.
    2 It must not rely on JavaScript.
    3 It must not require additional graphics.
    4 It must work on mobile and tablet touch devices.
    5 It must degrade gracefully in older browsers (IE7+) or when specific CSS3 properties are not supported.

    Best to read the article and look at the pictures.
    It must look great!

  • http://www.johnmanoah.com John Manoah

    Great article… actually it worked great in Chrome, i mean the graphics were smoother in Chrome than FireFox.

  • http://www.e-sushi.net/ Mike Edward Moras (e-sushi™)

    For those interested in learning who invented the technique, I can enlighten you: “none of the above”.

    The technique itself was first introduced (and used) around 1998, mostly with the help of javascript. Around 2001, CSS-only implementations started spreading like a wildfire. And a pure CSS3 implementation using alike 3D effects has been around for more than two years (at least). Mind that some implementations (like that “Meny” thing) still rely on javascript.

    I have to say that I am honestly shocked to notice some people here have not been aware of the earlier demos and (the obviously ignored) full-fledged website implementations. How can anyone have the nerve to randomly accuse the author of this article, just to promote one of many ego-pleasing demos?

    Let’s look at the details: this acticle shows a non-javascript, css3-only based implementation and therefore strongly differs from the “Meny” demo which relies on javascript. Case closed. There is no reason for anyone to play drama-queen.

    Now, go on and get a life… or at least a sip of fresh air to relax your minds.