Search code examples
htmlcssz-indexpseudo-element

z-index not working properly with pseudo-element


I tried to make a border around an anchor/button but somehow the z-index doesn't work in the following code, even though I assigned a position to either of them. It works with a negative z-index to an extent (but then other pseudo-classes such as :hover etc. won't work --> see my last question), but can someone please explain why the ::before pseudo-element keeps on showing on top of the button and not underneath it?

Here is my Code:

.start-coding {
  display: block;
  font-size: 1.3rem;
  color: white;
  background-color: black;
  padding: 0.4rem 1.8rem;
  position: relative;
  z-index: 5;
  border-radius: 5px;
  width: 100%;
}

.start-coding::before {
  content: '';
  background: linear-gradient(115deg, #4fcf70, #fad648, #a767e5, #12bcfe, #44ce7b);
  border-radius: 5px;
  position: absolute;
  top: -3px;
  left: -3px;
  right: -3px;
  bottom: -3px;
  z-index: 1;
}
<a href="#" class="start-coding">Start Coding</a>


Solution

  • That is because you have positioned your pseudo-element absolutely in the <a> element, and this causes it to be stacked on top of the text node, which has static positioning.

    To solve this issue, simply wrap the inner text with <span> and then add this rule:

    .start-coding > span {
      position: relative;
      z-index: 2;
    }
    

    Even better: you don't even need to add z-indices to both ::before and the nested <span>, since they come in an order that ensures that, when they are placed in a stacking context, the <span> will always be on top (since it comes after the ::before element in the DOM tree). See example:

    .start-coding {
      display: block;
      font-size: 1.3rem;
      color: white;
      background-color: black;
      padding: 0.4rem 1.8rem;
      position: relative;
      z-index: 5;
      border-radius: 5px;
      width: 100%;
    }
    
    .start-coding::before {
      content: '';
      background: linear-gradient(115deg, #4fcf70, #fad648, #a767e5, #12bcfe, #44ce7b);
      border-radius: 5px;
      position: absolute;
      top: -3px;
      left: -3px;
      right: -3px;
      bottom: -3px;
    }
    
    .start-coding>span {
      position: relative;
    }
    <a href="#" class="start-coding"><span>Start Coding</span></a>