Jason asks the CSS Guy if Dan Cederholm’s navigation is really “bulletproof”

Jason B. writes:

In Dan Cederholm’s book Bulletproof Web Design, chapter 2 gives a method for creating a horizontal nav system much like you see on his simplebits.com site. I’ve determined that the example he gives has a flaw (I think). It seems to create a quirk in the page that allows you to slide slightly to the right. So if all my divs are set to widths of 100% in a fluid layout, the nav ul expands to what looks like 110% width throwing the page all out of whack.

Even when I downloaded his example files from the book, the issue existed in those files too.

I’ve already responded to Jason via email, and I believe he’s got everything working ok, but I thought it might be helpful to post what Jason was seeing, and how to accomodate for it.

I downloaded the sample code that Cederholm provides on his web page and looked at Chapter 2 navigation example. In IE6, IE7, FF2 Mac, FF2 Win, and Safari, a horizontal scrollbar appears:

Bulletproof Navigation
Bulletproof Navigation

The scrollbar stays no matter how wide or narrow any of the above browsers are expanded. When scrolled, it’s just more of the red stripe. I asked Jason for clarification on the issue he was having, and he confirmed that was the same problem on his site.

The HTML, when simplified, looks like this:

<ul id="nav">
   <li><a href="/">Intr</a></li>
   <li><a href="/">About</a></li>
   <li><a href="/">News</a></li>
   <li><a href="/">Sponsors</a></li>
</ul>

The CSS for the ul looks like this:

#nav {
   float: left;
   width: 100%;
   margin: 0;
   padding: 10px 0 0 46px;
   list-style: none;
   background: red url(img/nav_bg.gif) repeat-x bottom left;
}

Adding float:left; to the ul#nav allows the ul to completely contain the floated <li> tags within it. width:100%; forces the <ul> to be as wide as the containing parent (in this case, the entire body).

The problem becomes apparent once padding is assigned to the left of ul#nav. padding: 10px 0 0 46px; means that the left side of the ul#nav now has 46 pixels of padding. When the above browsers render the <ul>, they don’t factor in the side padding for the width:100%, so once padding is applied, it appears as if the <ul> is wider than 100%.

What happens when we increase the left padding from 100px to 46px?

Bulletproof Navigation
Bulletproof Navigation

The tabs (or floated <li> tags), are pushed further from the left, and the scrollbar indicates a slightly wider window.

What happens when we decrease the left padding to from 46px to 0px?

Bulletproof navigation
Bulletproof navigation

The tabs are flush against the left, but no scrollbar.

We don’t want our tabs to be flush left, we want them to be 46 pixels from the left edge. There’s more than one way to do this. I’m going to discuss just one of them.

Leave ul#nav with no left/right padding, but add some left margin to the first list item.

#nav {
	float: left;
	width: 100%;
	margin: 0;
	padding: 10px 0 0 0;
	list-style: none;
	background: red url(img/nav_bg.gif) repeat-x bottom left;
	}
#nav li {
	float: left;
	margin: 0;
	padding: 0;
	font-family: "Lucida Grande", sans-serif;
	font-size: 55%;
	}
#nav li:first-child {
	margin-left: 46px;
	}

Unfortunately, IE6 does not support the :first-child pseudo-class. If you don’t care, you may choose not to accommodate IE6. Personally, I feel it’s too early to ignore IE6. So I would suggest adding a class of “firstitem” or something like that to the first <li> tag in the list. Then style the CSS appropriately.

#nav {
	float: left;
	width: 100%;
	margin: 0;
	padding: 10px 0 0 0;
	list-style: none;
	background: red url(img/nav_bg.gif) repeat-x bottom left;
	}
#nav li {
	float: left;
	margin: 0;
	padding: 0;
	font-family: "Lucida Grande", sans-serif;
	font-size: 55%;
	}
#nav li.firstchild {
	margin-left: 46px;
	}

Here’s the result:

Bulletproof navigation
Bulletproof navigation

Looks much like the first screenshot, right? In all browsers, yes, except in IE6. Here’s what it looks like there:

Bulletproof navigation
Bulletproof navigation

In IE6, another bug comes into play – the IE Double Float-Margin Bug. Basically, our 46px margin is interpreted as 92px in IE6.

To accomodate for that, you could use conditional comments to serve IE6 an addendum stylesheet. Chances are, you will come across other display inconsistencies with IE6, and the IE6-only sheet will be worth it’s weight in Google stock. In the new sheet, tell IE6 that the margin for li.firstitem is only 23px (half of 46px), and IE6 will display it as 46px.

// this code would be in an IE6-only style sheet
#nav li.firstchild {
	margin-left: 23px;
	}

Done. Finally.

After all that, you might see why Cederholm chose not address this in Chapter 2 of his book. If I were just starting to toy with the idea of using CSS for layout, and had to read about all this hackery, (and keep in mind, I’m still in Chapter 2!), I’d put the book down and learn Flash instead. Cederholm wanted to show how flexible CSS menus can be – how they can be resized and still keep their aesthetic and functional integrity. He achieved it. His menus are, as he defines the word, bulletproof.

As I’m sure Cederholm is aware, there is plenty of time for working through implementation hurdles after the reader is sold on the concepts.