February 13th, 2008 - by Paul OB

Quite often I need to be in two places at the same time but it’s just not possible in the real world. Luckily however this doesn’t apply to some CSS techniques and in this article we will explore an often used CSS technique that allows portions of the same element to appear to be somewhere else.

If you are unsure of what I mean then take a look at this tooltip example.

CSS ToolTip

As you can see from the example above as soon as you rollover the anchor link a nice little tooltip box appears. I’m sure many of you know how this is done already but we’ll just explain the basics a little before we move on to some more interesting examples.

The technique works by targeting a nested element that is held inside the anchor and then using absolute positioning on that element to move it somewhere else. In order to have a consistent effect we create a local stacking context on the anchor by adding position:relative to it. This means that the nested absolute element will now be placed in relation to that anchor and not the viewport (should there be no other positioned parents).

The first thing we need to do is to create the HTML that will be used for this demonstration.

  1. <p class="example1">Roll your mouse over the following <a href="#null">Rollover here please<span> As you can see a nice little message box appears over the text and provides some more information.</span></a>.</p>

In the above snippet we have nested a span element inside an anchor element and it will provide the text for our tooltip message. In order for the text inside the span not to show, we will simply hide it until it’s called for. There are a number of ways of hiding the text such as using display:none, visibility:hidden or using an off screen measurement such as position:absolute;left:-999em.

The method I am going to use (which I find the most reliable) is to use visibility:hidden to hide the text. You may think that display:none would be better but IE can be a little buggy at times with this and the visibility method is more stable. The difference between display:none and visibility:hidden is that display:none will collapse the space that the element occupied to nothing; as though the element didn’t exist at all.

Visibility, on the other hand, just makes the element visible or invisible but still preserves the space that the element occupies. This won’t be a problem in our tooltip demo because the element is absolutely positioned anyway and therefore takes up no space in the flow of the document.

The CSS we need for his short demo is as follows:

  1. .example1 a{position:relative;}/* set stacking context -*/
  2. .example1 a span{
  3.     visibility:hidden;/* hide message initially*/
  4.     position:absolute;
  5.     top:-75px;
  6.     left:-70px;
  7.     width:250px;
  8.     padding:5px;
  9.     background:#829900;
  10.     color:#fff;
  11.     border:2px inset green;
  12.     text-decoration:none;
  13. }
  14. .example1 a:hover{visibility:visible}/* ie bug needed to make span show*/
  15. .example1 a:hover span{visibility:visible;}/* show image on hover*/

First, we set the anchor to position:relative, as already mentioned, and this ensures the tooltip is placed in relation to wherever the anchor is at that time.

The next step is to place the span absolutely at the position we require and to hide it. The code for that is pretty straight forward and is self-explanatory.

Finally, the clever bit: when the anchor is hovered we change the visibility of the span to visible. We do this by addressing the span while the anchor is in the hover state and using a descendant selector to target the span. Although IE6 only understands the :hover pseudo class on anchor elements (a elements with an href attribute) we can still effect a change on nested inner elements by using the anchors hover state. I should also point out that you can do these hover effects on any element in other browsers except IE6 and under (even IE7 is ok) as they support :hover on nearly all elements.

The code that does all the work is simply as follows:

  1. .example1 a:hover span{visibility:visible;}/* show image on hover*/

Couldn’t be simpler could it?

IE6 Bug

However, if you try that code in IE6 and under you’ll notice that the tooltip doesn’t appear. This is due to a bug and IE6 (and under) won’t effect a change to the span unless something is also changed on the anchor at the same time. As we don’t want to change anything on the anchor, I use this “all purpose” solution and simply set the hover state of the anchor to be visibility:visible.

So our hover section now looks like this:

  1. .example1 a:hover{visibility:visible}/* ie bug needed to make span show*/
  2. .example1 a:hover span{visibility:visible;}/* show image on hover*/

The visibility:visible on the anchor has no detriment to the example because it affects nothing as the anchor was already visible but it cures the bug and can be used in any situation where you need this effect. The result of the above can be seen here in this tooltip example or in Figure 1 below.

Figure 1
tooltip1.jpg

Two Places at the Same Time

An interesting thing to note is that the absolute element can still be the target for the href in the anchor and if we change the element to be visible at all times we can have an effect like this:

Figure 2
tooltip2.jpg

We have the anchor text split in two places which was done with the following code:

  1. <p class="example1"> <a href="#null">I am the main anchor here<span>And I am way over here </span></a></p>
  1. .example1 a{
  2.     position:relative;
  3.     background:yellow;
  4.     color:#000;
  5.     padding:5px;
  6. }
  7. .example1 a span{
  8.     position:absolute;
  9.     top:200px;
  10.     left:100px;
  11.     width:250px;
  12.     padding:5px;
  13.     background:yellow;
  14. }

It’s important to note that the yellow background color on the span must be explicitly defined to match the anchor’s background because backgrounds are not inherited (even though most people think they are). A background will only show in a child element when that child element happens to be over the parent’s background because the background’s default is actually transparent. It is not inherited at all. Anyway, I digress and let’s now set up a hover effect for the anchor.

  1. .example1 a:hover,
  2. .example1 a:hover span{background:red}

When either the span or the anchor is hovered both elements will change at the same time as can be seen in Figure 3 below or this live example.

Figure 3
tooltip3.jpg

When hovered, both parts turn red even though they are miles apart and the space between them is not active either. You may say that looks very nice but what actual use could this present in everyday layouts?

As usual it only takes a little bit of imagination and some interesting effects can be used to enhance your boring old web page. You could have text on either side of a fixed width section and as you traverse down one side the corresponding text also highlights. Or you could have the disjointed section as a graphical element or pointer effect. There are some more advanced examples here that might be of interest.

All Change

We will look at a couple of other examples that utilize the methods above so that you can see you are really only limited by your own imagination.

First of all take a look at the final result of our first task. The screenshots below show first the normal state and then the highlighted state as an element is hovered.
Figure 4
tooltip4.jpg

Figure 5
tooltip5.jpg

Granted it’s not an earth shattering demo — the effect is that as soon as you enter the menu the whole menu changes color and each menu item is highlighted as you roll down the menu.

This example needs to be broken down in two parts because unlike the tooltip examples above each line of text is a different anchor and we need to change the background color of the ul on hover which is not possible in IE6 and under without using script. However we will get around this so don’t worry.

For compliant browsers that allow hover on elements other than anchors we will use the following code:

  1. #nav{
  2.     list-style:none;
  3.     margin:20px;
  4.     padding:0;
  5.     width:200px;
  6.     position:relative;
  7.     float:left;
  8.     background:red;
  9.     border:1px solid #000;
  10.     border-top:none;
  11. }
  12. #nav li{
  13.     float:left;
  14.     clear:left;
  15.     width:200px;
  16. }
  17. #nav li a{
  18.     float:left;
  19.     width:180px;
  20.     text-decoration:none;
  21.     padding:3px 10px;
  22.     color:#000;
  23.     border-top:1px solid #000;
  24. }
  25. #nav:hover li{background:#ccc;}
  26. #nav li a:hover,#nav li.current a{background:orange}
  1. <ul id="nav">
  2.     <li><a href="#">Test 1</a></li>
  3.     <li><a href="#">Test 2</a></li>
  4.     <li><a href="#">Test 3</a></li>
  5.     <li><a href="#">Test 4</a></li>
  6.     <li><a href="#">Test 5</a></li>
  7.     <li><a href="#">Test 6</a></li>
  8.     <li><a href="#">Test 7</a></li>
  9.     <li><a href="#">Test 8</a></li>
  10. </ul>

There is nothing really clever here except that when the nav is hovered we change the whole background color of the nav and then change just the background color of the menu item.

The whole work is done here:

  1. #nav:hover li{background:#ccc;}
  2. #nav li a:hover,#nav li.current a{background:orange}

(I set up a current class in case you wanted one as a default.)

The CSS is straight forward and needs little explanation. We use the pseudo hover class on the ul (#nav) and then do the same for the anchor. It provides a nice subtle effect and you could substitute the background colors for images if you wished to make it more interesting.

How Can This be Done in IE?

Unfortunately as already explained we can’t use the same process for IE6 and under because they only understand hover on anchor elements. Therefore we are going to use the aforementioned disjointed tooltip method to place a background over the whole navigation but we are going to do this from inside the anchor. Doesn’t sound possible, does it?

The first thing we need to do is to change the HTML so that we have an extra element inside the anchor so that we have something we can re-position.

  1. <ul id="nav">
  2.     <li><a href="#"><span></span>Test 1</a></li>
  3.     <li><a href="#"><span></span>Test 2</a></li>
  4.     <li><a href="#"><span></span>Test 3</a></li>
  5.     <li><a href="#"><span></span>Test 4</a></li>
  6.     <li><a href="#"><span></span>Test 5</a></li>
  7.     <li><a href="#"><span></span>Test 6</a></li>
  8.     <li><a href="#"><span></span>Test 7</a></li>
  9.     <li><a href="#"><span></span>Test 8</a></li>
  10. </ul>

The nested span will be removed from the anchor and placed over the whole ul and will effect a change of background color to the whole ul. This is not quite as easy as it sounds. The navigation may be a fluid length as we don’t want to work with fixed heights but IE6 has another bug (wouldn’t you have guessed) in that an absolute element should be able to achieve 100% height of its parent. In nearly all other browsers you can set an absolute element to be 100% high of its relatively positioned parent and the absolute element will maintain pace.

IE6 (and under) doesn’t obey this rule and collapses the height:100% to height auto which is effectively zero (or line-height) in our demonstration. Therefore we are going to utilize another technique of mine first seen in my equal column examples. For this method we simply place the span at the bottom of the ul and give it a height so big that it will always fill the column. We hide any overflow by using overflow:hidden on the parent. This method doesn’t suffer from the “inpage links” problem that other equal column methods have suffered from.

Relative to What?

In the first tooltip example we placed position:relative on the anchor and placed the inner span in relation to the anchor. However, for this example we need to place the position:relative on the ul because we want all the spans to be positioned from the ul’s position and not each individual anchor’s position.

We are going to wrap the IE code in conditional comments so that only IE6 and under get it.

The revised full CSS and HTML is as follows:

  1. <ul id="nav">
  2.     <li><a href="#"><span></span>Test 1</a></li>
  3.     <li><a href="#"><span></span>Test 2</a></li>
  4.     <li><a href="#"><span></span>Test 3</a></li>
  5.     <li><a href="#"><span></span>Test 4</a></li>
  6.     <li><a href="#"><span></span>Test 5</a></li>
  7.     <li><a href="#"><span></span>Test 6</a></li>
  8.     <li><a href="#"><span></span>Test 7</a></li>
  9.     <li><a href="#"><span></span>Test 8</a></li>
  10. </ul>
  1. #nav{
  2.     list-style:none;
  3.     margin:20px;
  4.     padding:0;
  5.     width:200px;
  6.     position:relative;
  7.     float:left;
  8.     background:red;
  9.     border:1px solid #000;
  10.     border-top:none;
  11. }
  12. #nav li{
  13.     float:left;
  14.     clear:left;
  15.     width:200px;
  16. }
  17. #nav li a{
  18.     float:left;
  19.     width:180px;
  20.     text-decoration:none;
  21.     padding:3px 10px;
  22.     color:#000;
  23.     border-top:1px solid #000;
  24. }
  25. #nav:hover li{background:#ccc;}
  26. #nav li a:hover,#nav li.current a{background:orange}

IE only CSS inside conditional comments:

  1. <!--[if lte IE 6]>
  2. <style type="text/css">
  3. #nav{overflow:hidden;}
  4. #nav li a:hover span{
  5.     position:absolute;
  6.     width:200px;
  7.     background:#ccc;
  8.     left:0;
  9.     bottom:0;/* use bottom instead of top as it cures inpage link bug*/
  10.     z-index:-1;
  11.     height:100em;/* needs to be bigger than container will ever be*/
  12. }
  13. </style>

Here is the link again so you can see for yourself.

The #nav is given position:relative to create the local stacking context and overflow:hidden so that it hides the extra height of this absolute element. We use an absolute position of bottom instead of top as it avoids any issues with in-page links. Then we simply give the span a width and a background color. Lastly we give the span a z-index of -1 so that it moves under the foreground elements and doesn’t obscure our links.

It’s a simple effect but works most anywhere and can provide similar functions as shown in a previous article which used an image matrix for similar effects. I’m sure you can come up with more interesting examples.

Are You Regular?

For the last example in this article we will imitate an image map type effect which will allow us to have irregular shaped hot spots for our anchors. Usually all elements are rectangular and if you wanted to make an irregular shaped anchor you would only be able to approximate it by placing the nearest fit rectangle around the anchor.

Using our disjointed method we can use nested elements and offset them so that the shape that becomes the anchor’s hotspot is not regular. Obviously for a complicated shape this would involve using too many inner elements of various sizes to accomplish this and wouldn’t be viable so we are going to restrict the demo to at most two nested elements and create a navigation structure that can break over a couple of lines.

With this in mind take a look at the following demo.

Ignoring the contrived graphics you can see that as you hover over each item the hover effect hugs only that part of the sentence that is relevant. This can’t be done by any other means because you would have to have rectangular shape and that would include parts of the text that aren’t relevant to the current item. In the example above you have the hotspot starting halfway along one line and then wrapping to the next and sometimes even to a partial section of a third line.

This is all accomplished by offsetting elements that are nested inside the anchor and placing them over the irregular parts of the anchor. It’s a little bit fiddly because you have to work out all the co-ordinates for the positioning and then match that to the relevant background image position.

The above is in fact one single image and is shown in a smaller size in the screenshot below.

Figure 6
tooltip6.jpg

It is then just a matter of manipulating the background image positions so that we show only the part of the image that needs to be seen in each element.

I am not going to go into detail on this last demo as it uses the same techniques we have already used and most of the code is involved in placing the anchor at the required position and then ensuring that the nested elements (spans and ems) lie over their corresponding parts.

The final tricky part is also manipulating the correct part of the background image to show on hover but that is just a matter or working out all the co-ordinates beforehand.

It would not be possible to make this menu any other way (apart from image maps, etc) due to the irregular shape and although you could do something similar with normal background image swaps the hot spot areas would overlap areas that they shouldn’t.

As usual with my articles you should refer to the actual demos themselves for the full CSS and HTML (view source) and realize that we are discussing techniques here that you might find useful or just interesting. The examples are often contrived to show what can be done but in most cases you are only limited by your own imagination. I’m sure that you can come up with better examples than mine especially as my graphic skills are zero!

If you can’t figure out how the last example works or don’t understand some aspect of it then post here and I will try and clarify.

Have fun!

Be Sociable, Share!

5 Responses to “Disjointed CSS”

1 Erik Johansson

Now the designers can start imagine also menus.

Good work!

2 Paul OB

Thanks Erik :)

3 John

From an accessibility point of view, it would be better to use the off screen method with your first example otherwise AT users won’t have access to that content.

4 Paul OB

Hi John,

Yes I did mention the off-screen technique in the same paragraph and I have now updated the first example to show this method also. You are correct that the off screen method is better for AT users (screen readers etc) :)

[...] Hover Descendant Demo Hover Quirks Tutorial [...]

Share your thoughts...

mulberry sale spyder womens jacket cheap new balance 574 mulberry outlet cheap new balance 574 arcteryx outlet mulberry sale spyder womens jacket mulberry sale spyder womens jacket mulberry outlet mulberry outlet new balance 574

Popular Articles

Top 10 Commentators


Subscribe to this feed! Subscribe by Email!

Random Bits Podcast

You need to download the Flash player from Adobe

Blogs Worth Reading