TJKDesign: Home Page
Creative Commons License
This work is licensed under a
Creative Commons License.

If you've found this beneficial, consider making a donation through Paypal

Guild of Accessible Web Designers Logo
Valid XHTML 1.0!
Section 508
Web Standards
Tables-less Layout
Frames: a solution or a problem?
XML Feed
NN4.7 Safe!

ez-css Putting the 'less' in table-less layouts. css-101 logo
Bookmark this article at these sites:

TJKTabs Menu...

There is a great ALA article that discusses tabbed navigation. It shows how to design very stylish "scalable" Tabs.

After reading this article myself, I thought that this solution was very clever but was missing an important feature that the purely graphical counterpart offers: - da rollover effect!

Days went by after I wrote these pages. Then I discovered that there was a "sequel" to the original article and that there was also an article written by Philippe Wittenbergh that fixed the MSIE5 Mac issue. Duh! At first, I thought that I just wasted my time. Then, I found out that my own way to "get there" was very different and that my solution was the only one to be MSIE5 Mac and NN6 compatible.

Take a look at the horizontal menu at the top of this page (under the logo). It uses the technique described here. If one increases text-size, the images on each side of the links would spread apart; that's standard behavior and would not interfere with the text.

What makes this solution so "special" is that there are no images in between the links. In fact, I'm using 2 images inside each anchor.

That's the way we do the magic...

Everything lies in the CSS rule: a:hover {...}

The declarations inside this rule dictate the rollover effect, so I thought it was important to keep all element[s] I wanted to style within the anchor's "boundaries".
So I forgot about anchor[s] and li[s] elements altogether and went with... simple nested SPAN tags [read about this technique here].

Let's start with the following markup; it is a simple list in which we include two nested containers per anchor elements. It looks like this:

<ul>
<li><a href="#"><span></span><span>Home</span></a></li>
<li><a href="#"><span></span><span>About Us</span></a></li>
<li><a href="#"><span></span><span>Portfolio</span></a></li>
<li><a href="#"><span></span><span>Contact Us</span></a></li>
</ul>

This is the content of the CSS file:

ul {
margin:0;
padding:0;
list-style:none
}
li {display:inline}
li a {text-decoration:none}

Now we're setting class attributes for the SPANs and at the same time we're removing empty spaces between the list items to make sure MSIE does not create a gap between them [additions in red]:

<ul><li><a href="#"><span class="left">&nbsp;</span><span class="right">Home</span></a></li><li><a href="#"><span class="left">&nbsp;</span><span class="right">About Us</span></a></li><li><a href="#"><span class="left">&nbsp;</span><span class="right">Portfolio</span></a></li><li><a href="#"><span class="left">&nbsp;</span><span class="right">Contact Us</span></a></li></ul>

If I threw a non-breaking space in there, it is because some browsers won't reveal the background image of an empty container.

These classes contain the following declarations:

.left {
background-image:url(img/down.gif);
background-position:top left
}
.right {
background-image:url(img/down.gif);
background-position:top right
}

As you can see, these 2 rules share the exact same image; that image is used by both SPANs. It is either displayed at the top left corner of the element or at its top right corner. This is how we create our own sliding doors effect. Each SPAN's background image will stick on each side of the "box" as it expands or collapses.

The magic has begun...

Now we need to add some padding to reveal more of the background image [additions in red]:

.left {
background-image:url(img/down.gif);
background-position:top left;
padding:5px;padding-right:9px
}
.right {
background-image:url(img/down.gif);
background-position:top right;
padding:5px 20px 5px 0
}

Note that IE5/Win won't apply any padding unless we use a height declaration inside these rules. On top of this - in our example - IE5/Win shows another strange behavior: the cursor doesn't change into a hand when it is over a link.

We could use a hack in here to fix these browser specific issues but I prefer to use an IE CC, like this:

<!--[if IE 5]>
<style>
.left, .right {height:1px}
li a:hover {cursor:hand}
</style>
<![endif]-->

Make sure you place this IE Conditional Comment between the head tags of your document, below all your style declarations.

BTW, "hand" is not a valid value for the cursor property [but hey! It works!].

To add some "drama", we're using a wrapper (note that we could have used the List as well) to create a custom background for our "Tabs" [additions in red]:

<div id="navbar">
<ul>
<li><a href="#"><span class="left">&nbsp;</span><span class="right">Home</span></a></li><li><a href="#"><span class="left">&nbsp;</span><span class="right">About Us</span></a></li><li><a href="#"><span class="left">&nbsp;</span><span class="right">Portfolio</span></a></li><li><a href="#"><span class="left">&nbsp;</span><span class="right">Contact Us</span></a></li>
</ul>
</div><!-- /navbar -->

This is the CSS rule for our new ID selector:

#navbar {
width:100%;
background:black;
border-bottom:1px solid #333;
padding:10px 0 5px 0;
}

With this wrapper we've introduced a new problem, IE5/Win creates an unwanted gap below the list items. To avoid this "extra" padding, we need to add 2 declarations inside our IE Conditional Comment:

<!--[if IE 5]>
<style>
.left,.right {height:1px;
margin-bottom:-5px;}
li a:hover {cursor:hand}
#navbar {padding-bottom:0}
</style>
<![endif]-->

Just before creating the magic, we want to change the default color for our links. Doing so, we need to keep in mind that some User Agents out there won't show the backgound pictures of our nested SPANs, so we need to make sure the color we chose makes the links legible on the black background of our navbar DIV.
This is easy enough:

.left {
background-image:url(img/down.gif);
background-position:top left;
padding:5px;
padding-right:9px
}
.right {
background-image:url(img/down.gif);
background-position:top right;
padding:5px 20px 5px 0;
color:#f63
}

Now we do the heavy lifting:

li a:hover span {
background-image:url(img/up.gif) !important
}

Yes, this is it! It is that simple. We just swap background images.

Do not forget "!important" in there.

There is another IE issue, and this time it concerns IE6 too:
- If there is no rule declared for li a:hover, IE will swap background images only once, then the image "sticks". If you're browsing these examples with IE5/Win and didn't notice such behavior, it is only because the IE Conditional Comment in the pages already includes a declaration for the li a:hover rule. To take care of IE6, we need to swap color or background-color, i,e.:

li a:hover {color:yellow} /* MSIE fix */

One last thing we could add to the markup, is an ID selector to keep the current state of the navigation.
To do so, we create a rule for a new DIV that includes the exact same background declaration we used for li a:hover span and we make the text bold:

#current span {
background-image:url(img/up.gif) !important;
font-weight:600
}

In the markup, we need to give this ID to one of the list item [item #6 in this example]:

<li id="current"><a href="6.asp"><span class="left">&nbsp;</span><span class="right">Page 6</span>

We also use shorthand declarations and remove extra ";".

Read: "Hank like a pro!" if you want to implement this technique with a SSInclude.

Extra Browser's Issues I'm aware of...

Opera v6.05 does not reveal the backgound images of the nested SPANs unless we apply a float declaration in both of our classes. Unfortunately, that would break Opera 7 and MSIE Mac. I'm not aware of a hack for Opera v6, if there is one, the float declaration is an easy fix.

Also, because of this particular markup, it is almost impossible to get a classic background-color swap effect in this browser. I have a new version though that allows us to create 2 sets of rollovers [background-color swap and background-image swap] to end up with a solution that would degrade very nicely.

Opera 7 swaps the background image in only one of the 2 nested SPAN (the one containing the link).

As Douglas Bowman pointed out, if the user has his/her IE cache settings set to "Every visit to the page" instead of "automatically" [default setting] , the images flicker.

Note that changing cache settings in Netscape does not prevent such behavior.
The latter plus the fact that I tried a slightly different technique ["moving" a single image vs swapping 2] and got the exact same flickering effect makes me believe that the "problem" is not related to the browser's cache.

Breaking news: Minimizing Flickering CSS Background Images in IE6

As far as I know, the HTML markup is not a problem as long as NN4 does not see any fancy styles related to the nested SPANs

.