2

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>
kukkuz
  • 41,512
  • 6
  • 59
  • 95
DjangoJefe
  • 43
  • 5

2 Answers2

1

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

Temani Afif
  • 245,468
  • 26
  • 309
  • 415
0

You just need to add overflow: hidden; to the parent element.

.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%);
  overflow: hidden;
}

.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>
JasonB
  • 6,243
  • 2
  • 17
  • 27