Picture 33.jpg

The z-index bug in action

Although Internet Explorer 8 has been widely adopted, IE 7 is still the browser in use at my office, so all new projects must be compatible with it. Even though IE7 was already obsolete when we adopted it, it was a wonderful change from IE 6, because of the reduced need for CSS and javascript hacks, workarounds and compromises in general.

So it was a surprise to realize that an old Internet Explorer 6 stylesheet problem, the “z-index bug” still lingers on. You’ll know you’ve hit this bug when your drop-down menus fall UNDER elements that are lower down on the page. (…I should add: and there are no iframes or frames on the page).

There are several sites that do a fantastic job of telling you exactly why this happens. I’m just going to tell you how to fix it. In fact, if you want to jump to the fix right now, click here

What is the z-index bug?

Let’s say you have a layout like the one below, with a #header that goes across the top, and a #content area below it. Within #header is an element containing one or more drop-down menus (#menucontainer, below).

This is what you HOPE it would look like:

Firefox and Safari show this:

Picture 27.jpg

But, when you open Internet Explorer 7, you see this:

Picture 30.jpg

[click here to see live page]

The CSS stylesheet for the example above is shown below.

Note that there are several elements that have positioning assigned to them (#header#menucontainer#menu#content#positioneditem). Only #menu has z-index assigned, since that’s the natural thing you would try to do: try to force it up over the other elements. 

default test.jpg

The menus underlap items that come after them! 

HOW TO FIX IT

  • Add z-index to least common ancestor

    The simplest fix for this is to add a z-index setting of 1 or more to the “nearest parent” (least common ancestor) of the problem menu and overlapping elements.  In the diagram above, the nearest parent to #menu and #content is #outercontainer.

  • If that isn’t enough add z-index to positioned elements further down the DOM tree toward the menu element, until things straighten out.

    If adding z-index to the least-common ancestor did not fix the problem, it probably means some of the items are defaulting to automatic z-index values based on their order in the DOM. To fix this, work your way back down the DOM tree from the least common ancestor toward the menu element to the first positioned element, adding a z-index:1. Continue down to the next one adding z-index as needed until things improve, increasing the z-index by 1 as you go.

Example A. 

NO z-index assigned:

No z-index is assigned to any element. Items that need positioning have been positioned with either relative or absolute positioning. 

Scroll down to see what effect this has in various browsers.

no z-indexes.jpg

Firefox and Safari

Screen shot 2010-05-14 at 1.07.17 PM.jpg

Internet Explorer 7

 ie-A.jpg

In this case, they all show the menu underlapping the content area. 

#header and #content are in separate stacking contexts, and since #content comes last in the DOM, its context will always overlap items within #header.

Example B.  

z-index added to #outercontainer only

Same as before but z-index:1 has been added to the least common ancestor element:  #outercontainer.

Scroll down to see what effect this has in various browsers.

 B.jpg

Firefox and Safari

 Screen shot 2010-05-14 at 1.14.00 PM.jpg

Internet Explorer 7

ie-B.jpg

Well, it looks like we’re in about the same place as before – or are we? It may look the same, but there are some invisible changes happening to the way the browsers are perceiving order. Because the outermost ancestor now has a z-index assigned, it is creating a single big stacking context containing all the child elements and their sub-contexts. 

Example C. 

Just proving what’s happening!  I’ve removed the positioning on #content (doesn’t really need it anyway!) to show you how the positioning property is what causes the new stacking contexts to be generated.

Scroll down to see what effect this has in various browsers.

Screen shot 2010-05-14 at 1.17.38 PM.jpg

Firefox and Safari

Screen shot 2010-05-14 at 1.17.54 PM.jpg

Internet Explorer 7

ie-C.jpg

#content no longer generates its own stacking context, and drops back to z-index:auto ordering within the context created by #outercontainer. #positioneditem DOES create a new context because of its positioning property, and so jumps up over all other elements and contexts because it is the last element in the DOM. 

Example D.  

z-index added to next positioned element down from #outercontainer.

D-code.jpg


Firefox and Safari

D.jpg

Internet Explorer 7

ie-D.jpg

That seems to have done the trick! The z-index:1 added to #header caused #header to jump up over #content. If you were in a situation where you HAD to assign positioning to the #content element (which would cause IE to generate a new context there), then also give the #content element a z-index value of 0 to bring #content down lower than #header. Basically, do whatever you have to do to make sure that #header’s tree structure will all start at a higher level than #content‘s tree structure.

Here are some articles which will tell you in detail how stacking works: