With the introduction of CSS2 in 1998, HTML documents became three dimensional! Most of us have at one time or another used x and y coordinates. "X" specifies horizontal dimension and "Y" specifies vertical dimension. The "Z" dimension specifies how close or far away from the observer an object is; the third dimension!

Z-index Basics

Z-index only works on elements that have been positioned!

By using the CSS z–index property, each positioned element on the page can be layered over or under any other element. The z–index determines where in the stack each element is. Think of a Web page as a collage and the elements as variable-sized bits of paper. Where I place each bit of paper is determined by positioning (or lack thereof), and how much of it shows through the other elements is determined by the z–index.

The "Z" level of any positioned layer is expressed as a whole number, either positive or negative. Normal (default) HTML rendered elements exists on layer 0 (zero). Negative z–index numbers will place a positioned element behind the normal rendering layer. Positive z–index numbers will place a positioned element on top of the normal rendering layer closer to the observer.

When multiple positioned elements are layered one over another, the larger their z–index number - either positive or negative - the further from the default rendering layer the element is placed. A high positive number will be closest to the observer, and a high negative number will be furthest from the observer and behind the default rendering layer.

Note: The inability to render negative z-index values is one of the few times where Firefox (v. 1.5 and 2.0) fails! In Firefox a negative z-index value causes the element to vanish. On the other hand, IE6 displays the proper results. Until Firefox fixes this problem it is best to avoid negative z-index values.

In an HTML document, if no element has been styled with a z-index value, the default stacking order is layered as follows (beginning with elements furthest from the observer and progressing to those closest to the observer):

Positioned elements are rendered on top of the normal HTML layer by default. We have seen this in the examples on the previous pages. Here is a new Example page that shows the normal stacking order of five sibling DIVS when no z-index has been applied.

Applying z-index to Positioned Elements

I said it above but I'll say it again, z-index only works on elements that have been positioned (static positioning does not count).

If we wish to re-arrange the default stacking order of a positioned element we can use the z–index property to achieve the effect. An element with the following styling will be placed higher (closer to the observer) than another positioned element that is not styled with the z-index property.

#absoluteDiv { z-index: 1; position: absolute; top: 10px; left: 10px; }

This Example reverses the normal stacking order of the positioned elements that we saw in the previous example by applying z-index values. Note that the unpositioned element remains in the background in both examples.

Z-index Stacking Context

So far, the concept of using z-index has been pretty straightforward. I've demonstrated that an element is placed in front or behind other elements that share the same stacking context. This is what we normally think about when we change z-index -- we want something to move in front or in back of something else. The stacking context in our examples has been simple. None of the elements that were styled with the z-index property has a positioned ancestor element. Therefore they all exist in the same stacking context, that of the root element.

Even if we do have positioned ancestor DIVs which each contain a positioned nested DIV, as long as the ancestor DIVs do not contain any z-index of their own, the stacking context for the nested DIVs is still the BODY or root element. In terms of stacking contexts, the two ancestor DIVs are simply assimilated into the root element.

Only ancestor elements that have been positioned and styled with a z-index value can create a new stacking context. But when these conditions are met, the complexity of using z-index within a document increases and can cause frustration unless stacking context is understood.

When an ancestor element meets the conditions that create a new stacking context, it changes the way any nested element within that stacking context relates to the stacking order of all other positioned and indexed elements in the document. The new stacking context dictates that positioned elements nested inside this ancestor element will relate to each other in the manner we would expect when z-index is applied, but they no longer relate to positioned elements outside of the ancestor stacking context. It is the ancestor itself that determines how it, and all of it's nested elements, will 'stack up' against other external, positioned, and z-indexed elements in the document.

Below is a simple example of two positioned ancestor DIVs (green), each containing one positioned nested DIV. Given the following stacking context and hierarchy, the DIV in boldface type comes out on top. Take a good look at the z-index values.

Z-index Stacking Context

How can this be? DIV#4 has a z-index of 10! Why isn't it the one on top? And the answer is, the z-index of 10 only matters within the context of Ancestor DIV#3. If there were other nested DIVs inside DIV#3, and if they had z-index numbers lower than 10, then Div#4 would, indeed, come out on the top of the stack of elements nested within DIV#3.

In the example above, however, since the Ancestor DIV#1, has no z-index, it is assimilated into the root element and it's nested DIV#2 then competes on the same level with DIV#3. Since DIV#2 has a z-index of 2, and DIV#3 has a z-index of 1, DIV#2 wins! For a more comprehensive discussion of the z-index stacking context, check out the resource links below.

Fortunately we do not often run into the need for such complex assignment of z-index values, but if and when the time comes, remember to trace back through the hierarchy to determine whether there are any positioned ancestor elements that are styled with a z-index value. If there are, you have a separate stacking context to consider unless the competing positioned elements are all descendants of that same positioned and z-indexed ancestor.

This is a case where it really is important to know "Who's your daddy?"

Resources