511

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)

isherwood
  • 58,414
  • 16
  • 114
  • 157
DanSingerman
  • 36,066
  • 13
  • 81
  • 92

8 Answers8

498

Add position: relative to #over as shown in this snippet:

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

#under {
  position: fixed;
  top: 14px;
  width: 415px;
  left: 53px;
  border: 1px solid;
  height: 10%;
  background: #f0f;
  z-index: 1;
}
<div id="over">
  <P>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor
    in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
    </>
</div>

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

Fiddle

isherwood
  • 58,414
  • 16
  • 114
  • 157
stephenmurdoch
  • 34,024
  • 29
  • 114
  • 189
  • 15
    http://updates.html5rocks.com/2012/09/Stacking-Changes-Coming-to-position-fixed-elements is an excellent reference on how position fixed, absolute and relative interact with z-index. – Did Aug 29 '13 at 09:25
  • 2
    [Here is a fiddle](http://jsfiddle.net/A2xht/) demonstrating stacking context. It's explained [here](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context). – kdbanman Jul 17 '14 at 17:08
  • Removing `position: relative` from over element actually fixed my issue. – Alex G Jun 28 '16 at 18:47
216

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)
Mr_Moneybags
  • 3,927
  • 3
  • 19
  • 15
  • 2
    Thanks for this concise answer. `You cannot put a child element behind a root stacking context element`. I would expand that to *any* new stacking context element. This unfortunately puts an end to my sticky element having a shadow layer that activates on scroll since I can't set the z-index to show behind the sticky element due to the stacking context that `position: sticky` creates. – Kerry Johnson Apr 01 '22 at 14:01
32

Since your over div doesn't have a positioning, the z-index doesn't know where and how to position it (and with respect to what?). Just change your over div's position to relative, so there is no side effects on that div and then the under div will obey to your will.

Here is your example on jsfiddle.

isherwood
  • 58,414
  • 16
  • 114
  • 157
iamserious
  • 5,385
  • 12
  • 41
  • 60
28

This answer provides false information. Please review @Dansingerman's comment and example instead.


z-index only works within a particular context i.e. relative, fixed or absolute position.

z-index for a relative div has nothing to do with the z-index of an absolutely or fixed div.

isherwood
  • 58,414
  • 16
  • 114
  • 157
cusimar9
  • 5,185
  • 4
  • 24
  • 30
  • 3
    Can you expand on how z-index works in a particular context, and/or provide a reference? – DanSingerman Mar 07 '11 at 16:51
  • 14
    z-index affects the order of two divs even if one is position relative and the other is absolute. – Raffael Apr 23 '12 at 13:42
  • 69
    ***This answer is wrong.*** [Here is a fiddle](http://jsfiddle.net/A2xht/) demonstrating stacking context as it is explained [here](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context). @Dansingerman. – kdbanman Jul 17 '14 at 17:06
  • 1
    Thanks for your jsFiddle @kbdanman, it helped me understand the stacking context with a visual. – dhruvpatel Sep 16 '14 at 15:43
  • @kdbanman I thought the higher z-index went to the top? Why are the higher values on the bottom? – Joe Morano Feb 20 '15 at 05:17
  • 9
    @JoeMorano, Higher z is closer to the top, regardless of absolute or relative positioning. What matters is the level in the document tree. Divs 4, 5, 6 are children of div 3, while divs 1 and 2 are siblings of div 3. Div 1 has a higher z than div 3, so div 1 is on top of div 3 and all its children. Div 2 has a lower z than div 3, so div 3 and all of its children are on top of div 2 – kdbanman Feb 20 '15 at 19:34
20

Give the #under a negative z-index, e.g. -1

This happens because the z-index property is ignored in position: static;, which happens to be the default value; so in the CSS code you wrote, z-index is 1 for both elements no matter how high you set it in #over.

By giving #under a negative value, it will be behind any z-index: 1; element, i.e. #over.

Carlos Precioso
  • 2,731
  • 3
  • 21
  • 24
5

I was building a nav menu. I have overflow: hidden in my nav's css which hid everything. I thought it was a z-index problem, but really I was hiding everything outside my nav.

thedanotto
  • 6,895
  • 5
  • 45
  • 43
3

When elements are positioned outside the normal flow, they can overlap other elements.

according to Overlapping Elements section on http://web.archive.org/web/20130501103219/http://w3schools.com/css/css_positioning.asp

Khoa Nguyen
  • 1,540
  • 2
  • 15
  • 21
1

the behaviour of fixed elements (and absolute elements) as defined in CSS Spec:

They behave as they are detached from document, and placed in the nearest fixed/absolute positioned parent. (not a word by word quote)

This makes zindex calculation a bit complicated, I solved my problem (the same situation) by dynamically creating a container in body element and moving all such elements (which are class-ed as "my-fixed-ones" inside that body-level element)

Bakhshi
  • 1,299
  • 16
  • 25