Search code examples
htmlcsslayoutz-index

z-index and nested DOM elements (stacked context) overlay


How do I make div3 & div4 above div1 and div2 without using "ID" selector on CSS level?

enter image description here

.container {
    margin: 50px;
    padding: 20px;
    text-align: center;
    border: 1px dashed #999966;
}

.position {
  height: 120px;
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  margin-bottom: 10px;
  opacity: 0.8;
  border: 1px dashed #999966;
  background-color: #ffffcc;
}

.position .position {
  margin-top: 60px;
  margin-left: 100px;
  width: 50%;
}

.relative {
  position: relative;
  border: 1px dashed #669966;
  background-color: #ccffcc;
 }
 
.fixed {
  position: fixed;
  border: 1px dashed #669966;
  background-color: #e3e3ff;
  align-items: flex-start;
 }
 
.fixed.target-block {
  width: 200px;
  height: 300px;
  top: 130px;
  right: 140px;
  z-index: 999;
 }
 
<div class="container">
  <p>
    DIV: CONTAINER<br>
    position: relative;
  </p>

  <div class="position">
    <p>
      DIV #1<br>
      no position;
    </p>
    <div class="position relative">
      <p>
        DIV #3<br>
        position: relative;<br>
        parent
      </p>
      <div class="position fixed target-block">
        <p>
          DIV #4<br>
          position: fixed;<br>
          child
        </p>
      </div>
    </div>
  </div>
  
  <div class="position">
    <p>
      DIV #2<br>
      no position;
    </p>
  </div>
  
</div>


Solution

  • If we refer to the specification we can read this:

    1. All positioned, opacity or transform descendants, in tree order that fall into the following categories: ...

    2. All opacity descendants with opacity less than 1, in tree order, create a stacking context generated atomically.

    And in your case Div #2 will create it's own stacking context like Div #1 and since none of them is positioned with z-index you cannot achieve what you want by simply controling their child elements.

    So the only way I see here is to make one of the divs positioned and apply z-index to it or both of them positionned with different z-index. The purpose is to avoid following the tree order like specified above.

    .container {
      margin: 50px;
      padding: 20px;
      text-align: center;
      border: 1px dashed #999966;
    }
    
    .position {
      height: 120px;
      width: 100%;
      display: flex;
      align-items: center;
      justify-content: center;
      text-align: center;
      margin-bottom: 10px;
      opacity: 0.8;
      border: 1px dashed #999966;
      background-color: #ffffcc;
    }
    
    .position .position {
      margin-top: 60px;
      margin-left: 100px;
      width: 50%;
    }
    
    .relative {
      position: relative;
      border: 1px dashed #669966;
      background-color: #ccffcc;
    }
    
    .fixed {
      position: fixed;
      border: 1px dashed #669966;
      background-color: #e3e3ff;
      align-items: flex-start;
    }
    
    .fixed.target-block {
      width: 200px;
      height: 300px;
      top: 130px;
      right: 140px;
      z-index: 999;
    }
    <div class="container">
      <p>
        DIV: CONTAINER<br> position: relative;
      </p>
    
      <div class="position" style="position:relative;z-index:1;">
        <p>
          DIV #1<br> no position;
        </p>
        <div class="position relative">
          <p>
            DIV #3<br> position: relative;<br> parent
          </p>
          <div class="position fixed target-block">
            <p>
              DIV #4<br> position: fixed;<br> child
            </p>
          </div>
        </div>
      </div>
    
      <div class="position">
        <p>
          DIV #2<br> no position;
        </p>
      </div>
    
    </div>


    Some related questions:

    Stacking order of elements affected by opacity

    What has bigger priority: opacity or z-index in browsers?