0

If I have a floated <div id='1' style='float:right;'>controls and links</div> followed by a <div id='2' style='position:relative;'>lorem ipsum text here...</div>, <div> #2 lays on top of the <div> #1, blocking any mouse interaction. (If <div> #2 has a solid background color, it completely hides <div> #1, but still "wraps" around <div> #1.) Why is this so?

This remains true even if I set z-index values on both, trying to force the floated <div> #1 to the top.

There are four scenarios one can consider. I've put them all into this JSFiddle. (The JSFiddle also uses opacity to illustrate the stacking.)

  1. Floated <div> #1 has no z-index or position; the following <div> #2 also has no z-index or position. RESULT: <div> #1 is stacked on top of <div> #2, and mouse interaction is fine.
  2. Floated <div> #1 has no z-index or position; <div> #2 also has no z-index but has position:relative. RESULT: <div> #2 is stacked on top of <div> #1. No mouse interaction is possible.
  3. Floated <div> #1 has z-index:1000 but no position; the following <div> #2 has z-index:0 and position:relative. RESULT: <div> #2 remains stacked on top of <div> #1. No mouse interaction is possible.
  4. Floated <div> #1 has z-index:1000 and position:relative; the following <div> #2 has z-index:0 and position:relative. RESULT: <div> #1 is stacked on top of <div> #2, and mouse interaction is fine.

I have seen some similar SO questions, but nothing that exactly addresses this. I've also read a number of CSS float and positioning articles, but none seem to address this scenario.

BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Martin_W
  • 1,582
  • 1
  • 19
  • 24

2 Answers2

2

When dealing with stacking order, I recommend perusing the following list from section 9.9 of CSS2:

Within each stacking context, the following layers are painted in back-to-front order:

  1. the background and borders of the element forming the stacking context.
  2. the child stacking contexts with negative stack levels (most negative first).
  3. the in-flow, non-inline-level, non-positioned descendants.
  4. the non-positioned floats.
  5. the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
  6. the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
  7. the child stacking contexts with positive stack levels (least positive first).

First off, there are two things you need to remember:

  1. z-index has no effect on non-positioned elements. This includes floats. This is why setting z-index on your float, without positioning it, is not going to change anything.
  2. From my answer to a very similar question: "Floats do not establish stacking contexts on their own. They will only do so if they are positioned and have a z-index that is not auto (not counting any of the numerous other ways an element may do so)."

These two points cover why the float never appears in front of its positioned sibling in scenarios 2 and 3: the positioned sibling has stack level 0 (#6), which ensures that it's painted in front of the float (#4).

In scenario 1, the non-positioned sibling falls under #3, which is why it's painted behind the float (#4).

In scenario 4, floating becomes irrelevant altogether. You now have two positioned elements in the same stacking context, one with a greater stack level than the other (and, as implied elsewhere, greater by a completely unnecessary amount), so the one with the greater stack level is painted over the one with the smaller stack level.

Community
  • 1
  • 1
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
  • Wow. Takes a while to absorb this. I appreciate the reference to the right section of the CSS2 spec. One small point is that one cannot quite say floating becomes irrelevant, because in all four scenarios, there is text flow around the floated element. So the float is affecting layout... it's irrelevant with respect to stacking, but not with respect to final layout. – Martin_W Apr 07 '17 at 18:55
0

That is indeed how positioning works.

  1. With no positioning, elements behave as you expect.

  2. Positioning an element does put it in a new stacking context. So a relative div after a non-positioned one behaves as if it is stacked higher. (i.e. when you cause them to overlap in any way, the second one obscures the first one.)

  3. If you want z-index to work, the element must be positioned. So in scenario 3, the z-index simply does nothing, making it functionally the same as scenario 2.

  4. Therefore, scenario 4 is the solution you want.

Hope this explains things!

Edit: or not. See comments.

Mr Lister
  • 45,515
  • 15
  • 108
  • 150
  • 1
    A positioned element with z-index other than auto is not put in a new stacking context. It does establish a new stacking context, and its position in the stacking context it's in does change, but which stacking context it participates in does not change. – BoltClock Apr 04 '17 at 18:13
  • 1
    @BoltClock Sorry. I am not sure what the difference is supposed to be between "establishing a new stacking context" and "being put in a new stacking context". I made a [new fiddle](https://jsfiddle.net/xbqyr1nm/) that demonstrates the OP's original problem (no z-indexes, only position:relative); why would this go wrong then? Does the `float` have an effect too? If so, why isn't `float` mentioned, e.g. [here](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context)? – Mr Lister Apr 04 '17 at 19:16
  • For whatever reason, they split stacking into several subsections - floats are covered [here](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/Stacking_and_float). I always refer to the monolithic list in [section 9.9 of CSS2](https://www.w3.org/TR/CSS22/visuren.html#layers). In both links, it says that positioned descendants are always painted over non-positioned floats. – BoltClock Apr 04 '17 at 19:20
  • But this all takes place in the same stacking context - that of whichever ancestor the float and the positioned element are in. The stacking context established by the positioned element is completely irrelevant, since only the descendants *of* that positioned element are isolated within (and affected by) the new stacking context. – BoltClock Apr 04 '17 at 19:21
  • OK, now I get it. I think. Thanks! But you should have posted your own answer based on this, as mine turns out to have missed the mark. – Mr Lister Apr 04 '17 at 19:28