Overlapping And ZIndex

From CSS Discuss

Jump to: navigation, search

There seems to be some confusion about how to get one element to appear on top of another. Do you add z-index: 1 or z-index: 1000? Why do some items overlap others, no matter how high the z-index value goes? This page hopes to clear this up.

There's three different things that impact how elements overlap each other: stacking contexts, source order, and painting order. The most obvious issues come up when dealing with stacking contexts. But knowing the other two will help you figure out the more esoteric gotchas.

Stacking contexts

This is the hardest one to follow, and the one that trips up the most people, so we'll start with it.

When we think about how positioned elements get closer or further from the user, we take for granted that changing the z-index property will move it in front or behind its neighbors. But we rarely consider the question, "which neighbors?"

When you apply z-index to a positioned element, you do two things.

First, you say that the element is 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.

Second, you create a new stacking context for anything inside the positioned element. Once you've created a stacking context, any layering that happens inside that stacking context stays in that context. This is the part we forget.

One of the tricky things is figuring out which context two tags share. In a normal document, without any positioning, the document has exactly one stacking context -- the one created by html:

 <html>
   <head>
     <title>Title</title>
   </head>
   <body>
     <h1>Heading</h1>
     <p>Paragraph with <em>emphatic</em> text</p>
   </body>
 </html>

Now if the above document had the following CSS rules:

h1 {
 position: relative;
 z-index: 2;
}

p {
 position: relative;
 z-index: 1;
}

then h1 and p each create new stacking contexts, but relate to each other in terms of the stacking context created by the root of the document, html:

http://www.michael4css.info/images/wiki-stacking/relative.gif

In this case, we could say that the h1 is in front of the p, because the h1's z-index is higher than the p's, and they are inside the same stacking context.

Now, if we add the following rule, nothing changes:

em {
 position: relative;
}

because we haven't applied a z-index to the em rule, no new stacking context is created. But if we do, as in

em {
 position: relative;
 z-index: 1;
}

then a new stacking context is created inside the p:

http://www.michael4css.info/images/wiki-stacking/subrelative.gif

The text inside the em is closer to the user than the other text in the p, because of its z-index property. But because it is inside the p's stacking context, it is still lower than the text inside the h1. The following illustration shows the above document, from the side:

http://www.michael4css.info/images/wiki-stacking/subrelative-side.gif

Note: Adding bigger z-index values won't make an element in one stacking context rise above elements in another stacking context. Adding z-index: 1 is just as effective as adding z-index: 1000 if you don't have anything else positioned inside the same stacking context. If you want elements in one context to be higher than elements in another context, you have to raise the entire context, or put them into the same context.

To get the em in front of the h1, you'll either need to raise the p:

p {
 z-index: 3;
}

http://www.michael4css.info/images/wiki-stacking/p-above-em.gif

or remove the z-index from the p rule and increase the z-index of the em rule. This gets rid of the stacking context created by the p tag, so that the em tag and the h1 tag share the same stacking context:

h1 {
 position: relative;
 z-index: 2;
}

p {
 position: relative;
 /* z-index: 1; */
}

em {
 position: relative;
 z-index: 3;
}

http://www.michael4css.info/images/wiki-stacking/em-above-h.gif

When dealing with positioning, the stacking context is probably the hardest thing to remember. But once you have that idea down, you're good to go.

Source order

This is the easiest concept. There are two different ways of looking at an HTML document. One is by reading, from top to bottom, to see which tags start before which tags. For example, in a document that reads like this:

 <html>
   <head>
     <title>Title</title>
   </head>
   <body>
     <h1>Heading</h1>
     <p>Paragraph with <em>emphatic</em> text</p>
   </body>
 </html>

The source order says that the tags are defined in the following order:

  1. html
  2. head
  3. title
  4. body
  5. h1
  6. p
  7. em

The other way to look at this is in tree order where you keep track of not only which tags start first, but also which tags are inside other tags. With the document above, the tree order is:

  1. html
    1. head
      1. title
    2. body
      1. h1
      2. p
        1. em

This tells us that not only is head defined before body, but that title is defined inside head.

This may seem pretty uninteresting, but it directly impacts how the third concept works.

Stacking levels inside of stacking contexts

Normally, adjusting the z-index property and keeping track of stacking contexts is all you need to worry about. But occasionally you'll run into a situation where one box paints over another, even though there's no positioning involved. This happens because of how data is stacked inside of a stacking context.

Just to make things confusing, the specs call this concept stacking levels. I think of it in terms of painting order, where the browser paints one part of the page, then paints another level on top of that, and so on.

The specs define 7 painting layers. Starting from back to front, they are:

  1. The borders and background of the current stacking context
  2. Positioned descendants with negative z-index
  3. Nonpositioned block-level descendants with no z-index property defined -- paragraphs, tables, lists, and so on
  4. Floating descendants and their contents
  5. Nonpositioned inline content
  6. Positioned descendants with no z-index, z-index: auto, or z-index: 0
  7. Positioned descendants with z-index greater than 0

Note: All but the most up-to-date browsers reverse the first and second rule, so that positioned elements with negative z-index are painted behind the stacking context's borders and background. (This is because the CSS 2.1 specification significantly changed the stacking context behaviour defined in CSS 2.)

Note: IE6 and IE7 incorrectly apply z-index: 0 to all positioned elements. The 2.1 spec says that positioned elements that are z-index:auto should remain z-index:auto unless explicitly changed. See: http://tjkdesign.com/articles/z-index/teach_yourself_how_elements_stack.asp

Some of the above rules are pretty straightforward, like how positioned items with lower z-index are painted before positioned items with higher z-index. But some of the other rules aren't as obvious:

  • Source order counts. All other things equal, items later in the source order will paint over items earlier in the source order. If you think of it in terms of painting it makes sense -- the browser paints item a, then item b, and so on. This is useful for effects like overlapping boxes to prevent gaps from appearing.
  • Inline elements paint over floats. In a given stacking context, if you have an inline element next to a float, and that element has a negative margin that makes it overlap the float, the inline element will paint on top of the float. This can be an interesting effect.
  • Positioned elements paint on top of everything else if they don't have negative z-index. This means everything, including floats. This can be quite useful if, for example, you want something to paint on top of everything else, but you want a child of that item to be behind everything else. For that, you can position that element relative, with no z-index, and then position the child with a negative z-index. The first rule would paint the overlapping item above floats etc., while not creating a new stacking context. The second rule would push the child behind everything else.
Personal tools