Is it possible to set the stacking order of pseudo-elements below their parent element?
Pseudo-elements are treated as descendants of their associated element. To position a pseudo-element below its parent, you have to create a new stacking context to change the default stacking order.
Positioning the pseudo-element (absolute) and assigning a z-index value other than “auto” creates the new stacking context.
#element { position: relative; /* optional */ width: 100px; height: 100px; background-color: blue;}
#element::after { content: ""; width: 150px; height: 150px; background-color: red;
/* create a new stacking context */ position: absolute; z-index: -1; /* to be below the parent element */}
<!DOCTYPE html><html><head> <meta charset="utf-8"> <title>Position a pseudo-element below its parent</title></head><body> <div id="element"> </div></body></html>
::before pseudo-element stacking order issue
The contents of the div
, which include the two pseudo-elements and the p
element, participate in the same stacking context (relative to the div
). This is because, as you note, all three of them are statically-positioned; in other words, not positioned at all. (Yes, these elements do stack along the z-axis while in flow; you simply cannot manipulate their stack levels using z-index
because they're not positioned.)
Here's a summary1 of the order in which the various parts are drawn, bold emphases where relevant to your question:
Each box belongs to one stacking context. Each positioned box in a given stacking context has an integer stack level, which is its position on the z-axis relative other stack levels within the same stacking context. Boxes with greater stack levels are always formatted in front of boxes with lower stack levels. Boxes may have negative stack levels. Boxes with the same stack level in a stacking context are stacked back-to-front according to document tree order.
Within each stacking context, the following layers are painted in back-to-front order:
- the background and borders of the element forming the stacking context.
- the child stacking contexts with negative stack levels (most negative first).
- the in-flow, non-inline-level, non-positioned descendants.
- the non-positioned floats.
- the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
- the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
- the child stacking contexts with positive stack levels (least positive first).
Since div::before
is inserted before the content of the div
, and div::after
is inserted after it, when they display inline in a static position they'll naturally follow this rule, even if sandwiching a block element (the ordering takes both block boxes and inline boxes into account).
Notice that, for obvious reasons, backgrounds are usually painted first, with the content overlaying them:
The
p
element, as a block-level element, has a background that's painted first (#3).The inline-level pseudo-elements are then drawn with their backgrounds over the
p
background (#5). In the formatting model, they are siblings of thep
element, so they all participate in the stacking context of thediv
and not that of thep
.The
div::before
pseudo-element (both its content and background) appears behind thep
text because it comes before thep
in the visual tree.The
div::after
pseudo-element (both its content and background) appears in front of thep
text because it comes after thep
in the visual tree.
As indicated in my comment, if you make the pseudo-elements display as blocks, the background of the div::before
will hide behind that of the p
element, but not the text; instead, the text of the div::before
will be positioned between the background and the text of the p
element. Also notice that the background of the div::after
is painted in front of that of the p
, while the content is painted frontmost. Again, this has to do with backgrounds being painted before, or behind, content in relation to the rules above.
1 A much more detailed description can be found in Appendix E of the spec.
Put Pseudo element behind parent
div {
position: relative; /* optional */
width: 100px;
height: 100px;
background-color: blue;
}
div::after {
content: "";
width: 150px;
height: 150px;
background-color: red;
/* create a new stacking context */
position: absolute;
z-index: -1; /* to be below the parent element */
}
Pseudo-elements are treated as descendants of their associated element. To position a pseudo-element below its parent, you have to create a new stacking context to change the default stacking order.
Positioning the pseudo-element (absolute) and assigning a z-index value other than “auto” creates the new stacking context.
CSS ::before pseudo-element not respecting z-index stacking context
::after
inserts its content immediately before the end of the tag it's applied to but still inside the tag, z-index couldn't be lower than the z-index of the tag, so your approach won't work. But you could do ::after
to the parent tag, which in your case has class 'circle'. As the inserted content will be relative to the wrapping tag, you should adjust the position of the contend related to this tag.
See a codepen example:
Codepen Example
See a snippet example here:
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.canvas {
background: #573d0e;
height: 100vh;
width: 100vw;
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.circle {
width: 70vmin;
height: 70vmin;
background: #ffffff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
position: relative;
}
.circle:after {
content: '';
position: absolute;
z-index: 1;
width: 15vmin;
height: 15vmin;
background: black;
border-radius: 50%;
top: 10vmin;
left: 12vmin;
box-shadow: 30vmin 0 #000;
}
.panda {
position: relative;
border: 1.5vmin solid black;
width: 45vmin;
height: 45vmin;
border-radius: 50%;
background: #fff;
z-index: 2;
}
.eyes {
position: relative;
> * {
position: absolute;
width: 11vmin;
height: 15vmin;
background: #000;
border-radius: 70px / 100px;
left: 8.7vmin;
top: 9vmin;
transform: rotate(12deg);
&:before,
&:after {
content: '';
position: absolute;
}
&:before {
width: 4vmin;
height: 6vmin;
background: white;
border-radius: 76px / 100px;
left: 5vmin;
top: 3.2vmin;
transform: rotate(348deg);
}
&:after {
width: 2vmin;
height: 3vmin;
background: black;
border-radius: 76px / 100px;
left: 6.3vmin;
top: 5vmin;
transform: rotate(348deg);
}
}
:last-child {
transform: scale(-1, 1) rotate(12deg);
left: 22.3vmin;
}
}
.snout {
position: absolute;
width: 25vmin;
height: 18vmin;
top: 23vmin;
left: 8.5vmin;
bottom: 5vmin;
background: #fff;
border-radius: 50%;
border: 1.5vmin solid black;
&:before {
content: '';
position: absolute;
width: 1.5vmin;
height: 5vmin;
left: 10vmin;
top: 7vmin;
background: black;
}
}
.nose {
position: absolute;
width: 10vmin;
height: 7vmin;
left: 5.7vmin;
top: 0.5vmin;
background: black;
border-radius: 50% 50% 48% 52% / 21% 21% 79% 79%;
}
.mouth {
position: absolute;
width: 9.6vmin;
height: 5vmin;
border-radius: 50%;
border-bottom: 1.5vmin solid black;
bottom: 1.6vmin;
left: 6vmin;
}
<div class="canvas">
<div class="circle">
<div class="panda">
<div class="eyes">
<div></div>
<div></div>
</div>
<div class="snout">
<div class="nose"></div>
<div class="mouth"></div>
</div>
</div>
</div>
</div>
Z-index with before pseudo-element
The ::before pseudo-element is placed inside the header element.
CSS Spec:
The :before and :after pseudo-elements interact with other boxes as if they were real elements inserted just inside their associated element.
Setting the z-index for the header element creates a new Stacking Context, so the new pseudo element you created can not float behind the header element, because it would have to go outside that Stacking Context.
I suggest that you simply precede the header element by another element, so it stacks correctly by default. Example.
z-index doesn't work with ::after/::before element?
You can remove z-index
from parent element and use negative z-index: -1
on pseudo element. If you want only green line on red line you need to remove white background from parent also DEMO
.or { border: 2px solid #8fc300; border-radius: 5px; color: #333; font-size: 17px; font-weight: 600; height: 34px; line-height: 26px; text-align: center; width: 34px; margin-top: 64px; margin-left: 20px; margin-right: 20px; background: #fff; /*For z-index - keep the green area on top*/ position: relative;}.or::after { background: red; content: ""; display: block; height: 116px; margin-left: 15px; margin-top: -68px; width: 4px; /*For z-index - keep the green area on top*/ position: absolute; z-index: -1;}
<div class="or"></div>
Changing stacking order for CSS pseudo element
As far as I understood you need this
#progBar {z-index: -2;}
#cOne::after { z-index: -1;}
#progBar { z-index: -2; background-color:#bdbdbd; padding:1.5vw; position:relative; height:9vw; } .progcapt { background-color: #526cfd; color: transparent; text-shadow: 0px 2px 3px #526cfd; -webkit-background-clip:text; font-family:'arial black'; font-size:3vw } #cOne { position:absolute; left:calc(50% - 2.5vw); top:calc(50% - 2.5vw); border-radius:5vw; height:5vw; width:5vw; border:1px solid #526cfd; text-align:center; display:flex; align-items:center; justify-content:center; box-shadow:0px 0px 3vw #526cfd; background-color:white;
} #cOne::before { position:absolute; width:50vw; height:1vw; background-color:rgba(82,108,253,0.5); content:''; z-index:-1; } #cOneRing { position:absolute; top:-calc(0.5vw + 1px); left:-calc(0.5vw + 1px); width:6vw; height:6vw; border:1px solid #526cfd; border-radius:6vw; }
<div id='progBar'> <div id='cOne'> <span class='progcapt'>1</span> <div id='cOneRing'> </div> </div> </div>
z-index issue while transforming after pseudo-element with transition
You are having an issue because the transform is creating a stacking context moving the pseudo element inside thus it can not more be behind the main element.
I would advise you to consider something else because relying on the pseudo element behind its parent element may create issue because the pseudo element can go behind other element.
Here is a basic example if I add a background to the body where you will partially see the pseudo element because it's behind the body.
button{ background-color:red; padding:10px 15px; border:none; transition: .5s; position:relative; color:white; bottom: 0; right: 0;}
button:hover{ bottom: -5px; right: -5px;}
button:hover:after{ bottom:0; right:0;}
button:after{ content: ''; transition:.5s; position:absolute; bottom:-5px; right:-5px; z-index:-1; width:100%; height:100%; background-color:blue;}
body,html { background:#fff;}
<button>test</button>
z-index not working properly with pseudo-element
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>
Related Topics
How to Stick a Footer to Bottom in CSS
Are Flex Items Block Level Element
Scss Extend a Nested Selector and Override the Nested Rulesets
Make Font Awesome Icons in a Circle
When Does CSS's !Important Declaration Not Work
Select All 'Tr' Except the First One
Switching CSS Classes Based on Screen Size
Next.Js Global CSS Cannot Be Imported from Files Other Than Your Custom <App>
Bootstrap Change Order of Columns
Font Weight Turns Lighter on MAC/Safari
How to Get the Nth Child of an Element Using CSS2 Selectors
Css: Bolding Some Text Without Changing Its Container's Size
Chrome Renders Colours Differently from Safari and Firefox
Select an Element with Empty Class Attribute (Class="") Using CSS