Surfin' Safari

Front Page  -  Technorati

September 15, 2004


Z-Index

Posted at 1:36 AM

Over on webstandards.org I found a link to a guide to z-index according to the CSS2.1 specification. Click here to see this guide.

I mention it because it accuses both the Gecko and KHTML engines of violating the CSS spec, but in reality the author simply does not understand how auto z-index works in CSS2.1.

Stacking contexts are established in three ways in modern browsers:

(1) The root element gets a context.
(2) Elements with opacity < 1.0 establish a stacking context (and a z-index of auto is changed to 0).
(3) A positioned element with a z-index other than auto establishes a stacking context.

In other words, being positioned (absolute/fixed/relative) does not mean you establish a stacking context! You must also have a non-auto z-index.

The normal flow contents of positioned elements with auto z-index are sorted in an enclosing stacking context as though they had z-index 0. Document order breaks ties. This is specified in section 9.9.1 of the CSS2.1 specification.

... a stacking level for positioned descendants with 'z-index: auto', and any descendant stacking contexts with 'z-index: 0'...

So in this example you have 4 blocks, two of them relatively positioned and two absolutely positioned.

The two relative positioned blocks each contain absolute positioned descendants. Because the two RP blocks have the same z-index (auto), they are sorted in document order. RP1 is therefore below RP2. AP1, the absolute positioned block inside RP1, has a z-index of 1. This guarantees it will be above both RP1 and RP2, since it is sorted in the root element's stacking context at a z-index of 1. RP1 and RP2 render just above the normal flow (z-index 0) level of the root stacking context, and therefore will always be below AP1 if it has a positive z-index defined.

Therefore the assertion that AP1 should render below RP2 is false, and Mozilla and Safari have the correct rendering.

In this example, Safari 1.2 on Panther does violate the spec regarding the positioning of AP2. AP2 should render above RP1 and RP2 in the example but below AP1. Internal Safaris actually render this correctly (we fixed this bug a long time ago actually), so future releases of Safari will be correct.

In the next example, both Mozilla and Safari have the correct rendering. The claim that only IE gets it right is false. IE gets it wrong. The RP blocks have a z-index of auto, and so they are below all of the absolute positioned blocks with positive z-indices in the root's stacking context.

The following quote should additionally make this clear. It's also from the CSS2.1 spec, section 9.9.1.

The root element forms the root stacking context. Other stacking contexts are generated by any positioned element (including relatively positioned elements) having a computed value of 'z-index' other than 'auto'.

In other words, when a block has auto z-index, it does not act as a stacking context for other positioned descendants.

So in the next example, Mozilla and Safari are once more correct. Because RP1 now establishes a stacking context, AP1 is sorted only within RP1's stacking context. RP1 is then sorted with AP2 in the root's stacking context. RP1 has a z-index of 11 and AP2 has a z-index of 20, so RP1 is below AP2. RP1 and AP2 are both above RP2 of course because RP2 has an auto z-index, and therefore is just above normal flow content in the root stacking context (at the 0 z-index level).

I hope this helps clarify how z-index works in modern browsers. As usual, track back if you have questions.

comment (59) -

Copyright © Dave Hyatt 2003, Design by Stéphane Curzi/ProjetsUrbain.com