Css – Interleaving non-siblings with z-index

cssz-index

I'm trying to have a sidebar menu overlap a content div, where the active menu item appears over the div and the non-active items would appear under. The intersection between a ul and div would be small, but the interleaving effect would create an illusion of depth.

I understand that z-index only applies to sibling elements. So the following doesn't work:

#menu {z-index:0}
#menu li.active {z-index:2}
#content {z-index:1}
<ul id="menu">
  <li class="active">Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>
<div id="content">Side content</div>

Is there a good way to do this without having to make each menu item a div on the same level as #content?

Best Answer

You want some li to appear at the front of a div, and the other ones at its back.

The only way to achieve this is making sure all the li and the div belong to the same stacking context. That means the ul must not create any stacking context, so don't set any z-index to it. See Which CSS properties create a stacking context? for what exactly should be avoided.

And then it will be easy: just set the z-index properties to the li and the div as desired. However, remember that z-index only applies to positioned elements, e.g. position: relative.

#menu > li.active {
  position: relative;
  z-index: 2;
}
#content {
  position: relative;
  z-index: 1;
}

body {
  margin: 8px;
  position: relative;
}
#menu {
  margin: 0;
  padding: 5px 0;
  list-style: none;
}
#menu > li {
  padding-left: 15px;
  border: 1px solid;
  background: yellow;
  margin: 4px 0;
}
#menu > li.active {
  position: relative;
  z-index: 2;
}
#content {
  position: absolute;
  background: blue;
  top: 0;
  left: 5px;
  width: 5px;
  height: 100%;
  z-index: 1;
}
<ul id="menu">
  <li class="active">Item 1</li>
  <li>Item 2</li>
  <li>Item 3</li>
</ul>
<div id="content"></div>

Related Topic