NKay
NKay

Reputation: 140

CSS let absolute element overlap parent's sibling without affecting scrolling/zooming behaviour

I have a specific use-case where I have a sidebar with some navigation items in a list and want to expand the elements on hover. The hovered item from the left div should overlap the right div.

This basically works if I make the list items absolute. The only problem is, that their position is no longer "good" when zooming or scrolling in the overflow. To fix this behaviour I can set a parent to relative. This however changes the stacking behaviour and I can no longer overlap the right div.

Is there any way to have the left items overlap the right div, without affecting their position when zooming or scrolling?

.container {
  display:flex;
}

.left {
  width:49vw;
  height:50vh;
  background-color:yellow;
  overflow-y:auto;
  overflow-x:hidden;
}
.right {
  width:49vw;
  height:50vh;
  background-color:green;
  position:relative;
  
  //position:absolute;
  //left:49vw;
  z-index:1
}

li {
  position:relative; //affects scrolling/zooming behaviour if not used
}
    
.item-text:hover {
        background-color:red;
        width:80vw;
        position:absolute;
        z-index:2;
    }
<div class="container">

  <div class="left">
    <div class="list-container">
      <ul>
        <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
      </ul>
    </div>
  </div>
  <div class="right">
 
  </div>


</div>

.container {
  display:flex;
}

.left {
  width:49vw;
  height:50vh;
  background-color:yellow;
  overflow-y:auto;
  overflow-x:hidden;
}
.right {
  width:49vw;
  height:50vh;
  background-color:green;
  position:relative;
  
  //position:absolute;
  //left:49vw;
  z-index:1
}

li {
  //position:relative; //affects scrolling/zooming behaviour if not used
}
    
.item-text:hover {
        background-color:red;
        width:80vw;
        position:absolute;
        z-index:2;
    }
<div class="container">

  <div class="left">
    <div class="list-container">
      <ul>
        <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
                <li><div class="item-text">
        1
        </div></li>
      </ul>
    </div>
  </div>
  <div class="right">
 
  </div>


</div>

jsfiddle

Upvotes: 1

Views: 3061

Answers (1)

christine.hack
christine.hack

Reputation: 38

You're on the right track with z-index. The tricky part about z-index is that it only overrides the stacking order WITHIN its parent element, and it only works for elements that have a non-static position property (anything other than default). In your CSS, the z-index on the .right div is 1 and the .item-text z-index is 2. Although it seems like it should work, the .item-text is still within the .left div, whose z-index defaults to auto, which puts it and all its contents below the .right div.

However, we can change this by setting the z-index on the parent elements. Below, instead of setting a higher z-index on the li element or its contents, I've set a higher z-index on the yellow div to make it (and its children) overlap its sibling. Then, the overflow of the yellow div will be above the green one.

You can read more about z-index here: https://philipwalton.com/articles/what-no-one-told-you-about-z-index/

  .container {
    /*We can either use flex positioning, or a combination of float and relative positioning 
below to achieve the desired layout.*/ 
     display:flex; 
  }

  .left, .right {
    display:inline-block;
    width:50%;
    height:200px;

  /* Below is an alternate way of arranging the elements to get the same result. 
I find this useful because it explicitly sets the position property.*/

    /*
    float:left;
    position:relative; 
    */
  }

  .left {
    background: yellow;
    z-index:2;
    overflow:visible;
  }

  .right {
    background: green;
    z-index:1;
  }

  li:hover {
    background: red;
    width:120%;
  }
<div class="container">
  <div class="left">
    <ul>
      <li>item 1</li>
      <li>item 2</li>
      <li>item 3</li>
      <li>item 4</li>
    </ul>
  </div>
  <div class="right">
  </div>
</div>

Upvotes: 1

Related Questions