views:

30

answers:

2

I'm attempting to create a tooltip-like system where a mouseenter event causes a div to show up which will overlay content. Unfortunately the issue I've run into is that content later in the DOM is not disappearing in IE7, while content earlier is disappearing correctly behind the z-indexed element.

Here is some sample code which illustrates the problem:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"&gt;
<html>
<body>

<style>
  .container { margin-top: 200px; }
  .node { float: left; width: 100px; height: 100px; background: #eee; margin-right: 50px; position: relative;}
  .two { position: absolute; left: -200px; top: 20px; width: 500px; height: 500px; background: green; z-index: 200;}
</style>

<div class="container">
<div class="node">
  <div class="one"></div>
</div>
<div class="node">
  <div class="two"></div>
</div>
<div class="node">
  <div class="three"></div>
</div>
</div>
</body>
</html>

The gist is rather simple. 3 identical gray boxes. Except in one of those boxes there is the tooltip (the giant green box). If you view this in Firefox, it works fine. If you view it in IE7 you'll notice that the green box overlays the first node, the second node, but the third node shows through. In addition if you set the z-index: 1 property on .node you'll notice that it exhibits the same behavior even in Firefox.

SOLUTION

Thanks to the response below I was able to get aligned on the right track. First, set the z-index of all tooltips to the highest element. Then set the z-index of all of the node elements to a lower number. I used 10 and 0. Next, on hover, set the z-index of the highest brother element needs to be higher than it's brothers, I used 5. In this case, if I want .child2 to be on top of everything, then I need to set the z-index of the highest parent which is a brother to everything I want to overlay (this could be multiple parents up the chain). In this case, it is node. So the z-index of the node which contains .two needs to be higher than the z-index of the other .node. Likewise, if the tooltip was at node -> subnode -> tooltip and that node was adjacent to similar trees, then I would need to set the node z-index (2 parents up).

A: 

IE incorrectly implements the stacking order algorithm. You'll have to dynamically alter the z-index of the "current" tooltip so whichever is the active .node, give it a z-index of say, 10 and when another tooltip is opened, reassign it to the initial value.

To my knowledge there is no true CSS solution without altering the source order.

meder
+1  A: 

Older IEs kicks off each new positional stack with a z-index of 0 if it's not set (rather than paying attention to a node's parent) -- the result is the last nodes in the markup always obscure earlier nodes.

In order to force older IEs to behave in cases like these, you must define a explicit z-index value for all nodes at the deepest nesting level they all have in common, and they must descend as you move through the document. Once you've done this, you can pull any item from the group ahead of all its peers.

Taking minor freedom with your example to simplify, let's say you had markup like this:

<div class="container">
 <div class="node1">
  <div class="child1"></div>
 </div>
 <div class="node2">
  <div class="child2"></div>
 </div>
 <div class="node3">
  <div class="child3"></div>
 </div>
</div>

You would want to z-index the "nodeX" elements in descending order down the entire page (they must all be at the same nesting level), and then you can give their children z-index values which will make sense.

Your base CSS would be like this:

/* parent nodes in descending order at same nest level */
.node1 { z-index: 99; }
.node2 { z-index: 98; }
.node3 { z-index: 97; }

/* child nodes contain tooltip data, z-index higher than parent */
.child1 { z-index: 101; display: none; }
.child2 { z-index: 101; display: none; }
.child3 { z-index: 101; display: none; }

... and when you want to display one of the child items as a tooltip, you would need to set its parent z-index above the other parents. In this case we want to activate the tooltip .child2, which lives inside .node2:

.node2 { z-index: 100; }
.child2 { display: block; }

When you set the .node2 to a z-index above all the other ".nodeX" items, it (and its children) should be able to obscure the nodes at the same nesting level.

Automating the Process

This can be a major pain to set up, obviously ... it's simple enough to set a few manual entries on something like a small hardcoded dropdown menu that needs to overlap itself, but if you are dynamically generating the page then you are probably savvy enough to use javascript to help you out.

The important thing is that the descending z-index values must all be at the same nesting level in your DOM tree, I can't stress this enough. To set the descending values for all of our nodeX elements in the example (starting at 99), I might use some jQuery code like this:

$(document).ready( function() {
    var zidx = 99;
    $('.container>div').each( function() {
        $(this).css('z-index',zidx);
        zidx--;
    });
});

Basically we just loop through elements at the specific level and give each subsequent element a z-index that is one lower. Obviously you'll need to pay attention to how many elements you might use and choose a range accordingly.

babtek
Thanks for the response. I did some more testing and determined that your answer was correct, but a bit overcomplicated. I edited my post with a more simplified answer.
Owen Allen