Search code examples
cssz-index

z-index not working with fixed positioning


I have a div with default positioning (i.e. position:static) and a div with a fixed position.

If I set the z-indexes of the elements, it seems impossible to make the fixed element go behind the static element.

#over {
  width: 600px;
  z-index: 10;
}

#under {
  position: fixed;
  top: 5px;
  width: 420px;
  left: 20px;
  border: 1px solid;
  height: 10%;
  background: #fff;
  z-index: 1;
}
<div id="over">
  Hello Hello HelloHelloHelloHelloHello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello
</div>

<div id="under"></div>

Or on jsfiddle here: http://jsfiddle.net/mhFxf/

I can work around this by using position:absolute on the static element, but can anyone tell me why this is happening?

(There seems to be a similar question to this one, (Fixed Positioning breaking z-index) but it doesn't have a satisfactory answer, hence I am asking this here with my example code)


Solution

  • This question can be solved in a number of ways, but really, knowing the stacking rules allows you to find the best answer that works for you.

    Solutions

    The <html> element is your only stacking context, so just follow the stacking rules inside a stacking context and you will see that elements are stacked in this order

    1. The stacking context’s root element (the <html> element in this case)
    2. Positioned elements (and their children) with negative z-index values (higher values are stacked in front of lower values; elements with the same value are stacked according to appearance in the HTML)
    3. Non-positioned elements (ordered by appearance in the HTML)
    4. Positioned elements (and their children) with a z-index value of auto (ordered by appearance in the HTML)
    5. Positioned elements (and their children) with positive z-index values (higher values are stacked in front of lower values; elements with the same value are stacked according to appearance in the HTML)

    So you can

    1. set a z-index of -1, for #under positioned -ve z-index appear behind non-positioned #over element
    2. set the position of #over to relative so that rule 5 applies to it

    The Real Problem

    Developers should know the following before trying to change the stacking order of elements.

    1. When a stacking context is formed
      • By default, the <html> element is the root element and is the first stacking context
    2. Stacking order within a stacking context

    The Stacking order and stacking context rules below are from this link

    When a stacking context is formed

    • When an element is the root element of a document (the <html> element)
    • When an element has a position value other than static and a z-index value other than auto
    • When an element has an opacity value less than 1
    • Several newer CSS properties also create stacking contexts. These include: transforms, filters, css-regions, paged media, and possibly others. https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
    • As a general rule, it seems that if a CSS property requires rendering in an offscreen context, it must create a new stacking context.

    Stacking Order within a Stacking Context

    The order of elements:

    1. The stacking context’s root element (the <html> element is the only stacking context by default, but any element can be a root element for a stacking context, see rules above)
      • You cannot put a child element behind a root stacking context element
    2. Positioned elements (and their children) with negative z-index values (higher values are stacked in front of lower values; elements with the same value are stacked according to appearance in the HTML)
    3. Non-positioned elements (ordered by appearance in the HTML)
    4. Positioned elements (and their children) with a z-index value of auto (ordered by appearance in the HTML)
    5. Positioned elements (and their children) with positive z-index values (higher values are stacked in front of lower values; elements with the same value are stacked according to appearance in the HTML)