Super sleek CSS3 only sliding menu tutorial

July 13, 2010 at 4:37 pm 4 comments

Sliding menuI’ve already shared with you some CSS tricks (like How to toggle the light on your website? or Simple website design using CSS). CSS 2 is certainly on a need to know basis before you should even think about adding some nice CSS3 stuff to your site. Anyway I believe that today is a good day to start spicing things up with a pure CSS3 sliding menu I’ve created … hot hot hot.

The dark side of CSS3 is that unlike CSS 2.1 it is splitted over several W3C specifications (some find it more convenient others don’t) that haven’t yet reached the standard status (i.e. they’re still drafts). Thus don’t expect this menu to work with every available browser and don’t use it in a production environment where the widest reachability (in terms of browsers and browser versions) comes as a priority compared to the cool stuff.

As of today I’ve tested my code under Windows and Mac systems, with the latest versions of the major browsers (Chrome 5 – stable – & 6 – dev channel -, Safari now in version 5, Opera 10.60, Firefox 3.6.6 & 4.0 beta 1, IE 8 and even IE 9 Platform Preview 3). Everything goes smoothly with webkit engines (Chrome and Safari), as well as with Opera. Firefox and its Gecko engines in version 3.6.6 doesn’t seem to support CSS3 transitions yet (but the menu degrades quite gracefully). However it is fully functional with Firefox 4.0b1. IE 8 unfortunately doesn’t support CSS3 at all while waiting for the very promising IE 9 which at least in PP3 still has some issues with CSS3 transitions and CSS3 transformations.

Now that I’ve set the scene let’s get started!

HTML the easy part

<nav>
	<ul>
		<li><a href="#">menu link 1</a></li>
		<li><a href="#">menu link 2</a></li>
		<li><a href="#">menu link 3</a></li>
		<li>menu</li>
	</ul>
</nav>

Very straightforward don’t you think? While we’re at it I’ve decided to use the new HTML5 nav element which purpose is to hold navigational information. Again not all browsers support HTML5 but here there is a very easy workaround. You could replace the <nav> ... </nav> tags with <div id="nav"> ... </div>.

Using a div with an id which is the name of the new element as defined in HTML5 is considered a good practice because then it’s easy to switch to HTML5 when widely available. Moreover from a CSS point of view it’s mainly a matter of replacing the #nav selector with the element nav selector (without the # sign) at least as long as you’re using the nav element only once on your web page (otherwise the style applies to all your nav elements).

One comment though on this short bit of HTML. While the first 3 list elements will be used as links and thus really for the navigation, the last li element will only serve as our menu title and will have dedicated styling and effects.

And … that’s it for the HTML :-).

CSS3 and the magic happens

Since the HTML part is very limited, as you may have guessed already, all the magic happens with the CSS. In this tutorial we are mainly going to use 3 of the multiple CSS3 specifications:

General styling: part 1

let’s start with some general properties:

nav {
	position: fixed;
	top: 100px;
	left: -600px;
	-moz-transition: left 0.5s ease-out;
	-webkit-transition: left 0.5s ease-out;
	-o-transition: left 0.5s ease-out;
	transition: left 0.5s ease-out;
}

nav > ul {
	margin: 0px;
	padding: 0px;
	list-style-type: none;
}

We use the nav element as a generic container for our menu and navigational links (i.e. what the HTML5 nav element is actually all about). The menu is set to a fixed position. In other words it’ll be fixed according to the browser window whether you’re scrolling up or down the page. The point of it is to always have the menu visible (anchored) in the browser window whatever the visible part of the page currently displayed (top or bottom). Of course you’ll need to set your page padding and margins accordingly so that the page content doesn’t step over the menu title.

The first property you may wonder about is left: -600px. It certainly needs a bit of clarification about what we try to achieve here. The list elements in our menu will actually be floated left so that they appear on the “same line” instead of each on its own line as in their default rendering. The goal is to hide the navigational links (i.e. the li elements that contain an anchor – a –  element) only living the last li element visible so it acts as our menu title or menu icon if you wish. Hence by positioning the nav element 600px far off the left side of the browser window we hide the biggest part of the iceberg. A direct corollary to this is that the list elements will need to be set with a width so we can precisely hide them all but the last one.

Actually there is another excellent reason to set the width of the li elements. Different browsers on different systems may not render default widths or font sizes exactly the same. You can’t just expect that a lucky guess for the global width of the first 3 li elements (in order to properly mask them) will look alike on a variety of OS / browser combinations (trust me I’ve tried). Thus although it’s a bit annoying (especially if your link titles have very different lengths), it’s cleaner to work with defined widths.

Then comes the first piece of CSS3 meat:

	-moz-transition: left 0.5s ease-out;
	-webkit-transition: left 0.5s ease-out;
	-o-transition: left 0.5s ease-out;
	transition: left 0.5s ease-out;

The CSS3 transition property is a shorthand for transition-property which in our example has a value of left, transition-duration which is set to 0.5s and transition-timing-function that has a value of ease-out. In other words instead of defining each of these properties we use a shorthand version which is followed by each individual property value space separated (left 0.5s ease-out).

But what does it all mean?

Basically a transition gives the browser instructions on how a CSS property change should be rendered. Here we choose the CSS transition-property on which to act and it’s the left property. Remember that the navigational part of the menu is hidden. Obviously we’ll want it to be displayed at some point like for instance when hovering the menu title. In order to do so, we’ll need to change the nav left property value to something within the browser window range. The left property change from the default value (-600px) to something appropriate will happen over a duration of 0.5s and follow the ease-out timing function. The timing function allows for the transition to change speed across its duration. The ease-out value means that the menu will decelerate towards the end of its transition.

Now what about the -moz-, -webkit- and -o- flavors?

As I already mentioned, at the date of publication of this tutorial, all CSS3 specifications are still drafts. Anyway all modern browsers have already implemented large parts of these drafts. Some of the properties have changed over time and thus each browser initially implemented specific versions of the up to come properties while waiting for the specifications to stabilize. To distinguish these specific implementations from the future standard ones, Mozilla, Webkit or Opera appended a prefix to the property names (-moz-, -webkit-, -o-). The issue is that some properties really are specific (i.e. non standard, this is very much true for Webkit), some have different syntaxes (have a look at Mozilla and Webkit gradients implementation for instance) and in the case of Opera sometimes it supports non prefixed CSS3 properties while some other times the prefix is required. In simpler words, if you want your CSS3 creation to be as much widely available as possible it is recommended to implement each flavor, while keeping as well the standard syntax. Remember that unsupported or unknown CSS properties should simply be ignored by a browser. Hence these “flavored” properties shouldn’t create any side effects which is exactly the point of the prefixes: it should only be supported by the browser which implements it.

To finish with the general styling part 1, we reinitialize any ul element which is a direct child of the nav element (notice the > in the CSS selector: nav > ul). No margin, no padding and no bullet whatsoever.

General styling: part 2

nav li {
	float: left;
	position: relative;
	width: 199px;
	height: 80px;
	border-left: 1px solid white;
	background-color: rgba(0,0,0,0.7);
	text-align: center;
}

nav a {
	display: block;
	position: absolute;
	top: 0px;
	left: 0px;
	width: 199px;
	height: 55px;
	padding-top: 25px;
	font-size: 1.4em;
	color: white;
	text-decoration: none;
}

The list elements style should be almost self explanatory. We want them on “one line” so we float them to the left. We give them a default size of 200 x 80 pixels (remember to add the 1px left border width to the element internal width – 199px – to get the element total width, considering the default margins and paddings are null). 3 navigational links x 200px here we’ve got our 600px to mask them off the browser window’s left. The background-color is set using a CSS3 property value (rgba) which basically defines a rgb color and gives it a transparency (in the form of a decimal value between 0 – transparent – and 1 – opaque).

A few things are worth explaining though.

  1. List positions are set to relative because the anchor elements position is set to absolute … and, I actually want the anchors position to be absolute relatively to their containers (i.e. the li elements) rather than the window. In order to do that the containers must be positioned as relative.
  2. I could have assigned the text-align: center; property to the anchor elements instead of the lists. However remember that the last list element (which we’ll use as a menu title) is not itself a link but I still want it’s text to be centered.

The anchors styling may seem a bit trickier to understand or at least you may wonder “what’s the point?”.

I’ve changed their display property to block while defining their width, height and padding because I want the anchors to be boxes of the same size as the li elements (with the exception of the li borders which explains why the anchors width corresponds to the lists internal width). Now the a elements are positioned to absolute with a top and left value both set to 0px. Since the list elements are positioned to relative, the a elements are absolutely positioned relatively to their container (i.e. the list elements) and not to the window. So the anchors top and left refers to the li elements. Since the anchor and list elements are both boxes of the same size, the anchors are actually on top of the lists and “cover” them completely.

“hum, sure, but then again what’s the point?”. Two main reasons:

  1. I didn’t want just the link text to be active but the whole anchor box instead. Without this trick your cursor could hover the link container (its list parent element) which itself isn’t clickable. In other words the only clickable part of the list items would have been their link text, and trust me it’s quite annoying. Now that the link is a box on top of the list element, the whole anchor box is actually clickable not just the link text.
  2. It gives us some additional styling options when hovering a link box. Instead of focusing only on the link text style, we can now style the link box as well (you’ll see that in a while).

Menu title dedicated style

Here we are going to focus on the menu title and use some new fun CSS3 properties.

nav li:last-child {
	border-style: none;
	width: 80px;
	height: 30px;
	padding: 0px;
	font-size: 1.4em;
	font-weight: bold;
	color: black;
	background-color: #0f0;
	-moz-border-radius-topleft: 5px;
	-moz-border-radius-topright: 5px;
	-webkit-border-top-left-radius: 5px;
	-webkit-border-top-right-radius: 5px;
	border-top-left-radius: 5px;
	border-top-right-radius: 5px;
	-moz-transform-origin: top left;
	-moz-transform: rotate(90deg) translateY(-30px);
	-webkit-transform-origin: top left;
	-webkit-transform: rotate(90deg) translateY(-30px);
	-o-transform-origin: top left;
	-o-transform: rotate(90deg) translateY(-30px);
	transform-origin: top left;
	transform: rotate(90deg) translateY(-30px);
}

Quite a few things to mention here…. Basically what we do is using the last li element in our navigation menu as a title. By default it is the only emerging and visible part of the menu which is supposed to slide to the right when hovered to show its navigational content. To make it something special that catches the eye we rotate it from horizontal to vertical. This has quite some side effects in the CSS that I’m going to explain.

First things first in order to select the last li element to apply a dedicated style to it I use one of the new CSS3 selector: last-child. I used to give most elements I want to interact with an ID but in the end the HTML code is less readable. Using last-child to get access to the last li element seemed particularly elegant and convenient. One could argue about the fact that this kind of selector is less efficient than accessing an IDed element. I guess it’s always a tradeoff issue between speed and readability … plus this tutorial is all about CSS3 :-).

Now rotating the last li element has 2 direct consequences (you’ll need to follow me and focus here):

  1. It’s width must be consistent with the other li elements height (80px) because it’s width once rotated becomes the element height.
  2. Similarly the rounded corners are the top left and top right ones that will become the top right and bottom right ones once rotated.

The difficulty here is to apply your style remembering that everything will be rotated by 90° clockwise. So what’s on the top will be on the right side of the element.

As an interesting side note here you can witness something I previously mentioned. See how the border radius properties are different for Mozilla and Webkit? Moreover there is no need for an Opera flavor this time because Opera supports the standard syntax as described in the current CSS3 2D Transforms draft. Yes it’s a bit of a mess while waiting for the specs to become standards.

One thing that may come as a shock in the transform CSS3 properties is certainly the addition of a translateY value. A little schema will help me explain better than words.

CSS3 rotate side effects 1/2 CSS3 rotate side effects 2/2

The transform axis origin is set to the top and the left of the menu title (the last li element). If you imagine a 90° rotation clockwise around this axis, as described in the schema, the last li element will “move back” on top of the previous li element by its height (which becomes its width after rotation). Because of this we need to translate the resulting box by 30px to keep the menu title at the tip (the far right) of the menu.

Make it all work

We’re almost done, all we miss is to do something when our menu is hovered.

nav:hover {
	left: 0px;
}

nav a:hover {
	color: red;
	-moz-box-shadow: red 0 0 20px inset;
	-webkit-box-shadow: red 0 0 20px inset;
	box-shadow: red 0 0 20px inset;
}

Here it comes, when we hover the nav element (our menu box wrapper) we change its default left property value from -600px to 0px. Simply speaking the navigation list elements which are far off the left of the browser window (and thus hidden) are slided to the right within the browser display range. This change in the left property value triggers the transitions that we’ve set initially and CSS3 does its magic.

I also gave you an example of the anchor elements styling so you can see the interest of giving the anchor elements a display: block; value, not to mention that there is no need for the cursor to be above the link text itself to click the corresponding menu list item.

Minor drawback and solution

There is actually one issue with this menu…. have you found it yourself :-).

The total width of the nav element is calculated before the last li element (the menu title) is rotated. Remember that once rotated the menu title width becomes its height and similarly its height before rotation becomes its width after rotation. Hence the true width of the nav element is longer than it visibly is at least as long as the menu title width (before rotation) is greater than its height (still before rotation).

Concretely the menu is sensitive to hover before the cursor really reaches the menu title. The largest the menu title width (before rotation and compared to its height) the longer this invisible “hoverable zone”. You can see the issue for yourself by slowly approaching the mouse cursor from the menu title’s right. You’ll see the menu’ll slide before the cursor is above the last li element. Another way to check this is to use the development tools that are usually provided with almost any last generation browsers. This invisible hoverable zone can simply be measured. Since the nav total width takes into account its children total width (before rotation) it is egal to the difference between the last li element width and height: 80px – 30px = 50px.

I didn’t anticipate this issue but the way I coded the menu actually allows for a simple and elegant solution. And here is yet another good reason to position the list elements as relative. We just need to move them all to the right by 50px to compensate. Obviously we’ll need to adjust the nav default and hover left property values as well.

Here are the changes that need to be made (highlighted in bold and orange):

nav {
	position: fixed;
	top: 100px;
	left: -650px;
	...
}

...

nav li {
	float: left;
	position: relative;
	left: 50px;
	...
}

...

nav:hover {
	left: -50px;
}

Conclusion

For your convenience you can find the full source code here (including the minor drawback solution mentioned above). I suggest you try the menu yourself and make some changes to the CSS3 code to make your own experience.  You can also try to scroll the page to see how the menu position is unaltered. I’ve normally added enough dummy text to give you the opportunity to scroll the page.  You can also try to resize the browser window. Since I’ve set margins and paddings to the body element and the main content div, the menu should alway be clearly visible with no text overlap. It’s also a good way to  see the transparency effect we’ve got thanks to the rgba property value.

Remember to minify your CSS in order to increase the responsiveness of your web sites. If you’re unaware of how to do it I suggest you check my previous post Minify your CSS files, speed and other SEO wizardry.

I hope you enjoyed this post, I’ve tried to explain everything in length so you can actually get something out of this tutorial. In case something is still unclear please ask, I’d be happy to help if I can. If you enjoyed the post feel free to leave a comment. Any improvement you may see (to the code or to the post in general) is also very much welcome, so thanks in advance for your feeback.

Advertisements

Entry filed under: Web Development. Tags: , .

Minify your CSS files, speed and other SEO wizardry Cross browser gradients with CSS3 and SVG

4 Comments Add your own

  • 1. Eric  |  June 28, 2012 at 10:59 am

    Unique menu! nice

    Reply
    • 2. p6ril  |  July 23, 2012 at 4:54 pm

      Thanks Eric 🙂

      Reply
  • 3. Julia Maria Sinelnikova  |  July 20, 2012 at 3:25 am

    How can I add sub-menu items that slide out?

    Reply
    • 4. p6ril  |  July 23, 2012 at 4:59 pm

      Ouch nice challenge, I’ll need to think about it. Not sure I can do it purely using css though but it would be a great enhancement. If I find a way I’ll post a follow up article.

      Thanks for the suggestion.

      Reply

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Trackback this post  |  Subscribe to the comments via RSS Feed


Calendar

July 2010
M T W T F S S
« Jun   Feb »
 1234
567891011
12131415161718
19202122232425
262728293031  

Most Recent Posts


%d bloggers like this: