0

i basically am trying to place the after and before pseudo elements behind anchor tag but they are still appearing on upfront , even though i have allocated them z-index

a{
    padding:1rem 1.5rem;
    background-color:whitesmoke;
    border-radius:12px;
    text-decoration:none;
    font-size:1.1rem;
    color:black;
    position:relative;
    z-index:2;
    user-select:none;
    cursor:pointer;
}
a:hover::after{
    content:'';
    position:absolute;
    height:50%;
    width:50%;
    bottom:2px;
    right:3px;
    box-shadow:5px 5px 40px 10px rgb(142, 224, 231);
    transition:all 0.5s;
    animation:shinny2 1s ease-in 1;
    animation-fill-mode:forwards;
    z-index: 0;
}
a:hover::before{
    content:'';
    position:absolute;
    z-index:0;
    height:50%;
    width:50%;
    top:2px;
    left:3px;
    box-shadow:-5px -5px 40px 10px rgb(142, 224, 231);
    animation:shinny1 1s ease-in 1;
    animation-fill-mode:forwards;
}
<a href="#">Foo</a>
DarkBee
  • 16,592
  • 6
  • 46
  • 58
lakshya
  • 1
  • 3

2 Answers2

2

Your <a> tag has the z-index of 2, which is higher than the default value auto (which is 0 if it has a stacking context).

When you assign its child pseudo elements to z-index: 0;, even they're smaller than 2, but they're not going to compare the z-index with its parent. (Otherwise you have to assign every of its ascendence with the same or higher z-index in order to show them)

Unless you give them a negative z-index, then they'll be shown behind the parent, because they're compared with the global stacking context instead of local.

a{
    padding:1rem 1.5rem;
    background-color:whitesmoke;
    border-radius:12px;
    text-decoration:none;
    font-size:1.1rem;
    color:black;
    position:relative;
    user-select:none;
    cursor:pointer;
}
a:hover::after{
    content:'';
    position:absolute;
    height:50%;
    width:50%;
    bottom:2px;
    right:3px;
    box-shadow:5px 5px 40px 10px rgb(142, 224, 231);
    transition:all 0.5s;
    animation:shinny2 1s ease-in 1;
    animation-fill-mode:forwards;
    z-index: -1;
}
a:hover::before{
    content:'';
    position:absolute;
    z-index:-1;
    height:50%;
    width:50%;
    top:2px;
    left:3px;
    box-shadow:-5px -5px 40px 10px rgb(142, 224, 231);
    animation:shinny1 1s ease-in 1;
    animation-fill-mode:forwards;
}
<a href="#">Foo</a>

But using a negative z-index has a drawback, that it will be appeared behind every other elements but not only its parent, unless they have a even lower z-index (negative z-index hell).

main {
  padding: 50px;
  background-color: gray;
}

a{
    padding:1rem 1.5rem;
    background-color:whitesmoke;
    border-radius:12px;
    text-decoration:none;
    font-size:1.1rem;
    color:black;
    position:relative;
    user-select:none;
    cursor:pointer;
}
a:hover::after{
    content:'';
    position:absolute;
    height:50%;
    width:50%;
    bottom:2px;
    right:3px;
    box-shadow:5px 5px 40px 10px rgb(142, 224, 231);
    transition:all 0.5s;
    animation:shinny2 1s ease-in 1;
    animation-fill-mode:forwards;
    z-index: -1;
}
a:hover::before{
    content:'';
    position:absolute;
    z-index:-1;
    height:50%;
    width:50%;
    top:2px;
    left:3px;
    box-shadow:-5px -5px 40px 10px rgb(142, 224, 231);
    animation:shinny1 1s ease-in 1;
    animation-fill-mode:forwards;
}
<main>
  <a href="#">Foo</a>  
</main>

If don't want to mess around with z-index, a workaround is to utilize translateZ to put the pseudo elements behind its content, that will only be affected in the local 3d stacking context. So you don't need to worry about the interations with other elements.

a {
  /* make sure the 3d stack works */
  transform-style: preserve-3d;
  display: inline-block;
}

a::before, a::after {
  /* put the pseudo elements behind the content */
  transform: translateZ(-1px);
}

main {
  padding: 50px;
  background-color: gray;
}

a{
    padding:1rem 1.5rem;
    background-color:whitesmoke;
    border-radius:12px;
    text-decoration:none;
    font-size:1.1rem;
    color:black;
    position:relative;
    user-select:none;
    cursor:pointer;
    display: inline-block;
    transform-style: preserve-3d;
}
a:hover::after{
    content:'';
    position:absolute;
    height:50%;
    width:50%;
    bottom:2px;
    right:3px;
    box-shadow:5px 5px 40px 10px rgb(142, 224, 231);
    transition:all 0.5s;
    animation:shinny2 1s ease-in 1;
    animation-fill-mode:forwards;
    transform: translateZ(-1px);
}
a:hover::before{
    content:'';
    position:absolute;
    height:50%;
    width:50%;
    top:2px;
    left:3px;
    box-shadow:-5px -5px 40px 10px rgb(142, 224, 231);
    animation:shinny1 1s ease-in 1;
    animation-fill-mode:forwards;
    transform: translateZ(-1px);
}
<main>
  <a href="#">Foo</a>
</main>
Hao Wu
  • 17,573
  • 6
  • 28
  • 60
  • that might be great idea but why isnt my code working out? i Am trying to figure out the reason also or else i will keeep on runing into it – lakshya Aug 23 '23 at 06:53
  • 1
    I don't think the "text" layer of your anchor actually has a z-index. You'd prolly want to wrap it with another element, e.g. span – DarkBee Aug 23 '23 at 06:56
  • text layer comes in the a tag ,so why will that z index not work on it – lakshya Aug 23 '23 at 06:59
  • @lakshya I've added more information about this solution and why your approach didn't work. – Hao Wu Aug 23 '23 at 07:17
  • @lakshya _"text layer comes in the a tag ,so why will that z index not work on it"_ - the text does not create a layer of its own, the `a` element _is_ the "layer" of the text. Text and the background color are _one_ layer here. – CBroe Aug 23 '23 at 08:20
0

Declaring z-index: -1 on the pseudo-elements does the job.

It appears that the z-index of the pseudo-elements is relative to the anchor. Giving the anchor z-index: 0 keeps the stacking order of the elements while allowing the pseudo-elements to be underneath only the anchor.

div {
  padding: 1em;
  background-color: aliceblue;
}

p {
  padding: 1.5em;
  background-color: ghostwhite;
}

a {
  position:relative;
  padding:1rem 1.5rem;
  font-size:1.1rem;
  text-decoration:none;
  background-color:whitesmoke;
  border-radius:12px;
  z-index: 0;
}

a:hover::after,
a:hover::before {
  content:'';
  position:absolute;
  height:50%;
  width:50%;
  z-index: -1;
}


a:hover::after {
  bottom:2px;
  right:3px;
  box-shadow:5px 5px 40px 10px rgb(142, 224, 231);
}

a:hover::before {
  top:2px;
  left:3px;
  box-shadow:-5px -5px 40px 10px rgb(142, 224, 231);
}
<div>
  <p><a href="#">Foo</a></p>
</div>
Tim R
  • 2,622
  • 1
  • 3
  • 19
  • it isnt working since i have applied a background to parent container of a tag – lakshya Aug 23 '23 at 07:10
  • i am using display gird in the container. does that affect it? – lakshya Aug 23 '23 at 07:33
  • @lakshya It appears that the z-index of the pseudo-elements is relative to the anchor. Giving the anchor `z-index: 0` keeps the stacking order of the elements while allowing the pseudo-elements to be underneath only the anchor. CSS Grid on the parent does not affect this. – Tim R Aug 23 '23 at 07:38