CSS

Go left. Go right. Stay in line.

My company recently did a complete overhaul of one client’s website, to structural markup. One of the things changed was that navigation is now done with ULs, which is a natural markup for it.

Navigation was a simple list of Home, Help, My account etc.

The client now plan to expand their Internet offer and replace the item Home with several business channels and wanted us to visualy separate those channels from items like My account or Help. They sent a mockup of the design they wanted, that imidiatelly put smile on my face.

Navigation mockup

This navigation bar is simple unordered list.

    <div id="topNav">
    
    <ul>
    
    <li><a href="#">Sports</a></li>
    
    <li><a href="#">Casino</a></li>
    
    <li><a href="#">Digital Derby</a></li>
    
    <li><a href="#">Search</a></li>
    
    <li><a href="#">Help</a></li>
    
    <li><a href="#">View BetSlip</a></li>
    
    <li><a href="#">Open account</a></li>
    
    </ul>
    
    <div class="clearer"> </div>
    
    </div>

Using CSS, we turned this into a horizontal list, by simply floating list items to the left. Before the redesign, this was achieved with tables. And that is why I smiled now. Using tables, this new effect client wanted would be horrible to achieve - either using all graphics, or using two table rows - one for upper part of the tabs (slanted one) and lower for the actual text.

With new markup, it was only a matter of style change and one graphic. The only change needed on the HTML markup was to add class="tab" to the list items that would be emphasized:

    <li class="tab"><a href="#">Sports</a></li>
    
    <li class="tab"><a href="#">Casino</a></li>
    
    <li class="tab"><a href="#">Digital Derby</a></li>

Now, let’s review the style, step by step. First, since all elements are floated, we need clearing element (without it background color of the bar would not be shown):

    .clearer {
    
    	height: 0;
    
    	line-height: 0;
    
    	clear: both;
    
    }
    
    * html .clearer {
    
    	font-size: 0;
    
    }

This works in all browsers except IE5/Mac. I don’t know why it ignores this, but since that is dying browser, I chose to ignore it.

Client’s request was to align betting channels on the left and remaining items on the right. Therefore, initially all items go to the right.

    #topNav ul {
    
    	margin: 0;
    
    	padding: 0;
    
    	list-style-type: none;
    
    }
    
    
    
    #topNav li {
    
    	margin: 0;
    
    	padding: 0;
    
    	list-style-type: none;
    
    	float: right;
    
    }

Now, we need some make-up - create yellow bar, positioned in the middle of the page, each item is centered and separated with vertical line, and items should change background-color when hovered.

    #topNav {
    
    	font-size: 85%;
    
    	font-weight: bold;
    
    	color: #000;
    
    	background-color: #ffe023;
    
    	margin: 0 auto;
    
    	padding: 0;
    
    	border: #000 1px solid;
    
    	width: 600px;
    
    }
    
    
    
    #topNav li {
    
    	text-align: center;
    
    	width: auto;
    
    }
    
    
    
    #topNav li:hover {
    
    	background-color: #ff9;
    
    }
    
    
    
    #topNav a {
    
    	text-decoration: none;
    
    	white-space: nowrap;
    
    	color: #000;
    
    	padding: 5px 10px;
    
    	border-left: 1px solid #000;
    
    	display: block;
    
    }

All this was already in place (apart from float:right which was float:left). See what we have so far. OK, now lets deal with slanted tabs. They go to the left, and background color is removed since we will use graphic to achieve slanted tab look.

    #topNav li.tab {
    
    	border: 0;
    
    	float: left;
    
    }
    
    #topNav li.tab:hover, * html #topNav li.tab a:hover {
    
    	background-color: transparent;
    
    }

See example with this style in place. Simplified version of Doug Bowman’s Sliding Doors technique is used to achieve tab effect. Because of the chosen design, we need just one graphic, and Pixy’s fast rollovers are used to achieve “change background color on hover” effect.

background image

    #topNav li.tab a {
    
    	background: url( images/toptab.gif ) no-repeat 100% 0;
    
    	margin-bottom: -5px;
    
    	padding: 7px 10px 8px 10px;
    
    	border: 0;
    
    	border-left: 1px solid #000;
    
    	position: relative;
    
    	left: -1px;
    
    	bottom: 5px;
    
    }
    
    #topNav li.tab a:hover {
    
    	background-position: 100% -50px;
    
    }

Update (Jan 29): Alex Robinson helped with Safari here. I previously had #topNav li.tab:hover a and Safari does not render that. Alex answered with the rule you see above, I re-checked in all other browsers, hence the update. All example files are updated too.

This also removed the need for IE hack that was there…I should’ve tried that my self.

This rule has several important parts. First, we do position:relative to give us ability to move the item around. Then, we move the item’s bottom edge up, so that tabs appear above the upper edge of the bar.

    	position: relative;
    
    	bottom: 5px;

Check it out now.

Now, we need to add left edge for the tabs. I also moved the item 1px to the left so that first item’s left edge overlaps with bar’s left edge.

    	border: 0;
    
    	border-left: 1px solid #000;
    
    	left: -1px;

Ok, since the tabs are now detached from the lower bar edge, we bring them down. Note the values: initially (in the #topNav a rule) we had 5px (padding-top) + 5px (padding-bottom) which is 10px. Now, we have -5px (margin-bottom) + 7px (padding-top) + 8px (padding-bottom) which is again 10px. If these two values don’t match, you will get gaps, which looks bad.

    	margin-bottom: -5px;
    
    	padding: 7px 10px 8px 10px;
Bugs and incomplete CSS2 support

As usual, a number of hacks is needed either due to bugs, obsolete or incomplete CSS2 support. First, we fix opera 6 problem with floated elements which don’t have explicit width. Then we revert that for newer browsers. This is known as Owen hack.

    
    /* Fix for Opera 6 */
    
    html>body #topNav li { width: 80px; }
    
    /* undo for CSS2-compliant browsers */
    
    head:first-child+body #topNav li { width: auto; }

Next comes IE/Win. It supports :hover only on A, so we need to use what we have. There is also Tan box model hack for non-standard box model in IE5.x.

    
    * html #topNav {
    
    	width: 600px;
    
    	width: 598px;
    
    }
    
    * html #topNav a {
    
    	width: 60px;
    
    	/* */
    
    	width: .1em; /* */
    
    }
    
    * html #topNav a:hover {
    
    	font-weight: bold;
    
    	background-color: #ff9;
    
    }

Actually, what I do in the middle style rule is a bit more complicated. Lets review it step by step. First, we need the fixed width for floated items in IE5/Mac or they will all have 100% width.

    	width: 60px;

This value is also used by IE 5.x and 6 on Windows. Windows versions of IE have additional bug - they will extend the width of the floated box to fit the content. We used that for our advantage here: IE 5.0x does not support white-space property (check the style for #topNav a way above) so this bug makes sure that items look OK. Since IE5.5 and IE 6 support it, we can additionally squeeze more room for items by setting item width to 0.1em, but making sure that IE5/Mac does not see this (using commented backslash hack).

    	/* */
    
    	width: .1em; /* */

And that does it - review the final example.

Update (Jan 29): I originally intended to have a double line between the tabs, so I used left: -1px;. Alex noted that double line can be removed if you use margin-left: -1px; instead, as shown in this example. Make sure to remove the left rule in that case, or the first item will hang 1px to the left of the bar.

Update (Feb 12): Too much reliance on side-by-side IE instalations is not good. IE 5.0/Win apparently has problems to move the tabs to the right. It does move the li.tab but a inside of it is left below the first right item (this does not happen on side-by-side install, but it sure does in Win98 with IE5 where I tested).

Solutions is this first rule:

    * html #topNav li.tab a {
    
    	/* */float: left;
    
    }
    
    * html #topNav a {
    
    	width: 75px;/* */width: auto; /* */
    
    	white-space: nowrap;
    
    }

Second rule is an update for better space handling. Only IE5/Mac needs specified width - all Windows versions work great with auto, thus leaving more space for items.