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;
    }
    <!DOCTYPE html>
    <html>
       <body>
          <div id="over">
             Hello Hello HelloHelloHelloHelloHello Hello Hello Hello Hello Hello Hello Hello Hello Hello Hello
          </div>  
          <div id="under">
          </div>
       </body>
    </html>

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)

9 s
9

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)

Leave a Comment