css: Horizontal CSS menu using a pointer and background images

OK, so the title is a bit too descriptive but I’m trying to make this post findable in case anyone out there needs to solve a similar problem. So this will be about… that’s right: creating a horizontal menu, using CSS and XHTML. Each menu item will have a small pointer underneath (an arrow if you will), and I want it all done using images, just to make it a little harder.

Here’s what I wanted the menu to look like:

menu

As you can see, some menu items are longer, some shorter. The menu sits in a gray bar and is separated from the remainder of the page by a green “tube”. I want the selected item and the hover state to be represented by a dark box with a pointer that breaks through the green tube.

At first I made the item an li which had the dark box as a background image and was immediately followed by an empty em tag which then had the pointer as a background image and was offset using relative positioning at 50% left.

A menu item looked a bit like this:

<li><a href="whatever">Homepage</a><em></em></li>

The problem was the positioning of the whole thing as in some browsers, the pointer would become detached from the dark box, and I couldn’t fix that with negative top margins because then the pointer would be offset in yet another browser. A mess. Plus, with this method, I needed a minimum width for each item, so I could then calculate the mid point to place the pointer. No good.

But there is quite a practical solution that came to me while thinking about the sliding doors method of making tabbed navigation menus: marvel then, at the ability to stack background images.

I couldn’t have used a single background image, because then, all my items would have to be the same width, since stretching the background image would distort the triangular pointer, so enter the bkg stack!

I took the li elements of an ul and styled them so they had the correct height: dark box plus triangular pointer. Then, I added a span inside each li, so I could style two overlapping elements with two different images. Then, in the CSS, I applied a background image to the li and another (the pointer) to the span. Keeping the stretching and centering is dead easy like this: you make the dark box around the text repeat on the x-axis and you turn off stretching on the pointer. Plus, you can easily center the pointer by just using “center” on the background declaration.

Here’s the HTML:

<div id=”menuarea”>
<ul class=”menu”>
<li class=”current”><a href=”#”><span>Homepage</span></a></li>
<li><a href=”#”><span>Funcionalidades</span></a></li>
<li><a href=”#”><span>Contactos</span></a></li>
<li><a href=”#”><span>SMS</span></a></li>
<li><a href=”#”><span>Chamadas</span></a></li>
<li><a href=”#”><span>Webmessenger</span></a></li>
<li><a href=”#”><span>Comunidade</span></a></li>
<li><a href=”#”><span>Passatempos</span></a></li>
</ul>
</div>

And the CSS:

#menuarea {height:40px; background-color:#F0F0F0; background:url(‘images/menuarea_background.gif’) repeat-x;}
.menu {width:73.84em; margin:0 auto; padding:6px 0 0 0; white-space:nowrap; list-style-type:none;}
.menu li {float:left; font-size:93%; text-align:center;}
.menu a {position:relative; display:block; text-decoration:none; float:left;}
.menu a span {display:block; color:#000; text-align:center; padding:9px 8px 8px 8px; cursor:pointer;}
* html .menu a span {cursor:hand; w\idth:66px;} /*IE Fix*/
.menu a em {display:none;}
.menu a:hover {color:#fff; background:url(‘images/menuhover_background.gif’) repeat-x; height:34px;}
.menu a:hover span {background:url(‘images/menu_pointer.gif’) top center no-repeat; height:17px;}
.menu a:hover {background-position:0 0;} /*IE fix*/
.menu .current a {color:#fff; background:url(‘images/menuhover_background.gif’) repeat-x; height:34px;}
.menu .current span {background:url(‘images/menu_pointer.gif’) top center no-repeat; height:17px;}

This is what the images look like:

menu area background The menu area background, which repeats along the x axis.

Menu item background The “dark box” that envelops each “current” or “hover” menu item

Menu pointer And the pointer.

As you can see, the dark box is as tall as a menu item plus the pointer and the pointer is the same height. They’re both transparent where they overlap and the pointer includes a bit of the green tube.

Overlapping background is a really powerful method of styling elements to make them look more complex than they actually are. It’s not *very* easy and you’ll notice the need for some IE 6 fixes and some weird height definitions that seem to make no sense. I know, I still can’t really explain some of it. But the truth is that the menu looks perfect in IE6, IE7 and Firefox for Windows as well as in Safari and Firefox for the Mac.

Source: nitrodesign.com

css: Horizontal Menus

Glossy Horizontal Menu screenshot 1

Mission

I believe that the only appropriate HTML markup for a menu is a list, namely unordered list marked by the <ul> tag. Styling such a list vertically is pretty simple, however what if you need a horizontal menu?

Well, the first option that came to my mind was setting list items property display to inline, instead of their default block. However that would prevent applying block-only styles like background, padding, etc. That’s why I took another approach — floats.

All following samples share the same HTML source code — a simple list resulting into this (unstyled) rendering:

And in all samples the list items are floated using the rule

li {float: left}

Solutions

1. Fixed padding

The menu items above have variable width and are separated by fixed padding (1em).

2. Variable padding

The menu items above are distributed evenly across the whole menu bar width. Each item has its width set to 24%.

3. Boxed items

In this sample are menu items of fixed width (6em) and fixed right margin (1em). Backgrounds and borders are applied to LIs instead of the whole menu.

4. Rollovers

Finally, the previous sample can be easily enhanced with rollover effect. The anchors inside the LIs have their width set to 100% and for their :hover pseudo class is set to a different background. Using a graphic background, this effect could be even more interesting.

Notes and compatibility issues

I’ve tested the page on Windows 95/98 in the following browsers:

  • IE 5.0
  • IE 6
  • Opera 6
  • K-Meleon 0.6 (Mozilla rendering engine)
  • Mozilla, nightbuild of 6/4/2002
  • Konqueror 3.0.0

All browsers listed above displayed the page the same way, except minor differences in default properties not set explicitly in the style sheet. During development I encountered the following issues:

  1. This approach is not suitable for older browsers like NN4 or IE4/Win. Developers are supposed to serve an alternate style sheet to those browsers or hide the style sheet from them at all (e.g. via @import).
  2. The menu has to be wrapped by a div that is used for styling background color, left margin/padding, etc. I’ve found no way to style the UL itself, because I can’t clear the float inside it. Thus the height of the OL always equals zero.
  3. The float property of the list items is cleared via

    <br clear="left">Attempts to do it by <div> failed in IE/Win and Opera for various reasons. It’s a pity, because the clear attribute is not allowed in the strict doctypes.

  4. For some strange reason, margin: 1em 0 applied on the div wrapped around a menu has no effect in IE/Win, so between the menus and the paragraphs just below them there are no empty space. It works fine in Opera and K-Meleon though.
  5. Because of IE5/Win bug, the div wrapping the menu width must be explicitly set to 100%. Otherwise the percents in the sample #2 are counted from the viewport’s width, not the width of the parent element.

Feel free to copy the code (style sheet is embedded into the HTML document) and use it as you want. Any comments, suggestion, fixes, etc. are highly appreciated at marek@sovavsiti.cz.

Thanks,

source: sovavsiti.cz