Search code examples
htmlcssbackgroundz-indexpseudo-element

Why does pseudoelement's background hide parent's?


The parent's background-color and the border-radius is hidden behind the pseudo element. Why is the pseudo element not behind the parent even though it has a z-index of -1?

.btn {
  text-decoration: none;
  background-color: royalblue;
  font-family: sans-serif;
  font-weight: bold;
  border-radius: 5px;
  color: white;
  display: inline-block;
  padding: 20px;
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.btn::after {
  content: "";
  display: inline-block;
  width: 100%;
  height: 100%;
  background-color: cornflowerblue;
  position: absolute;
  top: 0;
  left: 0;
  z-index: -1;
}
<a href="#" class="btn">Download free app</a>


Solution

  • The culprit is the transform property that create a stacking context thus your pseudo element will painted inside this stacking context and will logically be above the background whataver the z-index you will use.

    Remove transform to see the difference. I increased the border-radius and changed the color to better see.

    .btn {
      text-decoration: none;
      background-color: red;
      font-family: sans-serif;
      font-weight: bold;
      border-radius: 50px;
      color: white;
      display: inline-block;
      padding: 20px;
      position: absolute;
      top: 50%;
      left: 50%;
    }
    
    .btn::after {
      content: "";
      display: inline-block;
      width: 100%;
      height: 100%;
      background-color: cornflowerblue;
      position: absolute;
      top: 0;
      left: 0;
      z-index: -1;
    }
    <a href="#" class="btn">Download free app</a>

    In case you want the pseudo element to be below the parent you should avoid any properties that create a stacking context or it will be impossible.

    Or you consider another pseudo element to create the background layer and you will be able to control the stacking like you want:

    .btn {
      text-decoration: none;
      font-family: sans-serif;
      font-weight: bold;
      color: white;
      padding: 20px;
      position: absolute;
      transform:translate(-50%,-50%);
      top: 50%;
      left: 50%;
    }
    
    .btn::before,
    .btn::after{
      content: "";
      position: absolute;
      top: 0;
      left: 0;
      right:0;
      bottom:0;
      z-index:-1;
    }
    
    .btn::before {
      background-color: cornflowerblue;
    }
    .btn::after {
      background-color: red;
      border-radius: 50px;
    }
    <a href="#" class="btn">Download free app</a>


    Some related questions:

    Why elements with z-index can never cover its child?

    Is there any way to place z-index according not to its parent element