1

This has me stumped. I applied a border-right, border-left, and border-bottom to a div which has another Green BG color div inside of it. I set the z-index: 1 and position: relative on the parent div with the borders.

However, as you can see in the photo, only the LEFT border gets the z-index applied to it, whereas the RIGHT border doesn't get the z-index and falls behind the green div.

This ONLY happens if I have a width set on the inner-div wider than the outer div, and it only seems to prevent the first border-right from coming above the bg, as a repeating element doesn't suffer from this issue.

This makes no sense, and it's consistent across Chrome, Firefox, and Edge.

Is this some weird quirk / bug with CSS that I just discovered? Or am I somehow completely messing this up?

.flex-div {
  display: flex;
}

.outer-div {
    position: relative;
    border-right: 7px solid #cccccc;
    border-bottom: 1px solid #cccccc;
    border-left: 7px solid #cccccc;
    z-index: 1;
    max-width: 200px;
    flex: 0 0 200px;
}

.mid-div {
  width: 600px;
  z-index: -1;
  position: relative;
}

.inner-div {
    background-color: #00b989;
    width: 250px;
    height: 50px;
    display: inline-block;
    z-index: -1;
    position: relative;

}
<div class="flex-div"> 
  <div class="outer-div"> outer
    <div class="mid-div"> 
      <div class="inner-div">inner</div>
      <div class="inner-div">inner</div>
    </div>  
  </div>
  <div class="outer-div"> outer  </div>
  <div class="outer-div"> outer  </div>
<div>

Could you help me diagnose the reason why this is happening, and any workaround to get the borders on both the left and right of the outer-div to overlay the -inner-div?

z-index

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
TetraDev
  • 16,074
  • 6
  • 60
  • 61

2 Answers2

3

You cannot control the z-index in relation to its children because they are contained so (in a sense) inherit the z-index.

But you can make the children go behind their parent by setting their z-index to -1.

.outer-div {
    position: relative;
    flex: 0 0 200px;
    border: 7px solid #cccccc;
    max-width: 200px;
}

.inner-div {
    background-color: #00b989;
    width: 250px;
    height: 50px;
    position:relative;
    z-index:-1;
}
<div class="outer-div"> outer
    <div class="inner-div">inner</div>
  </div>

or you could apply overflow:hidden on the parent so that the green bar is hidden when larger (if that suits your needs)

.outer-div {
    flex: 0 0 200px;
    border: 7px solid #cccccc;
    max-width: 200px;
    overflow:hidden;
}

.inner-div {
    background-color: #00b989;
    width: 250px;
    height: 50px;
}
<div class="outer-div"> outer
    <div class="inner-div">inner</div>
  </div>
Gabriele Petrioli
  • 191,379
  • 34
  • 261
  • 317
  • Hi, that's really interesting. For some reason, the way my code is setup, that -1 z-index still doesn't seem to do it. I updated the original question with how the code in the app is - could you take a quick look and see what's different? I do need overflow for the specific scenario, otherwise that would work. – TetraDev Aug 14 '19 at 19:58
  • 1
    @TetraDev You didn't follow the answer, just remove the `z-index: 1` from outer-div. It's removed in the answer but wasn't mentioned and the first left border is visible in your original code is because it is border and the inner content started after it – Huangism Aug 14 '19 at 20:34
  • @Huangism Oh wow, I missed that detail... thanks for the clarification! – TetraDev Aug 14 '19 at 22:15
  • @Gabriele Petrioli Now I see how it works, great answer! This thread is full of CSS Geniuses :-) – TetraDev Aug 14 '19 at 22:16
2

To fix your issue you need to apply z-index to child elements not to parent element (keep the parent with z-index auto)

All the border on the top:

.flex-div {
  display: flex;
}

.outer-div {
    border-right: 7px solid #cccccc;
    border-bottom: 1px solid #cccccc;
    border-left: 7px solid #cccccc;
    max-width: 200px;
    flex: 0 0 200px;
}

.mid-div {
  width: 600px;
  z-index: -1;
  position: relative;
}

.inner-div {
    background-color: #00b989;
    width: 250px;
    height: 50px;
    display: inline-block;
    z-index: -1;
    position: relative;

}
<div class="flex-div"> 
  <div class="outer-div"> outer
    <div class="mid-div"> 
      <div class="inner-div">inner</div>
      <div class="inner-div">inner</div>
    </div>  
  </div>
  <div class="outer-div"> outer  </div>
  <div class="outer-div"> outer  </div>
<div>

All the border on the bottom

.flex-div {
  display: flex;
}

.outer-div {
    border-right: 7px solid #cccccc;
    border-bottom: 1px solid #cccccc;
    border-left: 7px solid #cccccc;
    max-width: 200px;
    flex: 0 0 200px;
}

.mid-div {
  width: 600px;
  z-index: 1;
  position: relative;
}

.inner-div {
    background-color: #00b989;
    width: 250px;
    height: 50px;
    display: inline-block;
    z-index: -1;
    position: relative;

}
<div class="flex-div"> 
  <div class="outer-div"> outer
    <div class="mid-div"> 
      <div class="inner-div">inner</div>
      <div class="inner-div">inner</div>
    </div>  
  </div>
  <div class="outer-div"> outer  </div>
  <div class="outer-div"> outer  </div>
<div>

To understand your initial issue you need to consider painting order and stacking context. By applying z-index to parent element you create a stacking context and since all of them have the same z-index they will be painted considering the tree order. So we print the first element and ALL its content then the second and ALL its content and so on.

Following this logic you will see the left border of the first and the right one will be hidden due to the overflow of the content then you will see the left border of the second element on the top of all the previous content and so on.

Here is a basic example to better illustrate your issue:

.box {
 border-left:10px solid red;
 border-right:10px solid red;
 height:50px;
 width:100px;
 display:inline-block;
 vertical-align:top;
 position:relative;
 z-index:1;
}
.box > div {
  width:130%;
  height:60%;
  background:blue;
}
<div class="box">
  <div></div>
</div><div class="box" style="margin-top:20px;">
  <div></div>
</div><div class="box" style="margin-top:30px;">
  <div></div>
</div>

Added some offset to parent element so you can clearly identify the painting order.

Now if you set positive z-index to only child elements they will all get painted on the top of the all the parent elements.

.box {
 border-left:10px solid red;
 border-right:10px solid red;
 height:50px;
 width:100px;
 display:inline-block;
 vertical-align:top;
}
.box > div {
  width:130%;
  height:60%;
  background:blue;
 position:relative;
 z-index:1;
}
<div class="box">
  <div></div>
</div><div class="box" style="margin-top:20px;">
  <div></div>
</div><div class="box" style="margin-top:30px;">
  <div></div>
</div>

And if you apply negative z-index they will all get painted behind:

.box {
 border-left:10px solid red;
 border-right:10px solid red;
 height:50px;
 width:100px;
 display:inline-block;
 vertical-align:top;
}
.box > div {
  width:130%;
  height:60%;
  background:blue;
 position:relative;
 z-index:-1;
}
<div class="box">
  <div></div>
</div><div class="box" style="margin-top:20px;">
  <div></div>
</div><div class="box" style="margin-top:30px;">
  <div></div>
</div>

Applying any z-index value to parent element will make what you want impossible since the child elements will get trapped inside the stacking context of their parent.


Related question for more details: Why can't an element with a z-index value cover its child?

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
  • Wow, excellent and amazing answer! You sir are a genius of CSS! Thank you, for the solution and explanation. It did work indeed :-D – TetraDev Aug 14 '19 at 22:14
  • While both answers here were correct, I accepted this one, because it gave a specific clarification of removing the z-index from the parent (or keeping it auto) which was easy to pass over, along with the detailed explanation. – TetraDev Aug 14 '19 at 22:17