I am trying to style a element with the :after
pseudo element CSS selector
#element {
position: relative;
z-index: 1;
}
#element::after {
position:relative;
z-index: 0;
content: \" \";
position: absolute;
width: 100px;
height: 100px;
}
It seems like the ::after
element can not be lower then the element itself.
Is there a way to have the pseudo element lower then the element itself?
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>
I know this is an old thread, but I feel the need to post the proper answer. The actual answer to this question is that you need to create a new stacking context on the parent of the element with the pseudo element (and you actually have to give it a z-index, not just a position).
Like this:
#parent {
position: relative;
z-index: 1;
}
#pseudo-parent {
position: absolute;
/* no z-index allowed */
}
#pseudo-parent:after {
position: absolute;
top:0;
z-index: -1;
}
It has nothing to do with using :before or :after pseudo elements.
#parent { position: relative; z-index: 1; }
#pseudo-parent { position: absolute; } /* no z-index required */
#pseudo-parent:after { position: absolute; z-index: -1; }
/* Example styling to illustrate */
#pseudo-parent { background: #d1d1d1; }
#pseudo-parent:after { margin-left: -3px; content: \"M\" }
<div id=\"parent\">
<div id=\"pseudo-parent\">
</div>
</div>
There are two issues are at play here:
The CSS 2.1 specification states that \"The :before and :after pseudo-elements elements interact with other boxes, such as run-in boxes, as if they were real elements inserted just inside their associated element.\" Given the way z-indexes are implemented in most browsers, it\'s pretty difficult (read, I don\'t know of a way) to move content lower than the z-index of their parent element in the DOM that works in all browsers.
Number 1 above does not necessarily mean it\'s impossible, but the second impediment to it is actually worse: Ultimately it\'s a matter of browser support. Firefox didn\'t support positioning of generated content at all until FF3.6. Who knows about browsers like IE. So even if you can find a hack to make it work in one browser, it\'s very likely it will only work in that browser.
The only thing I can think of that\'s going to work across browsers is to use javascript to insert the element rather than CSS. I know that\'s not a great solution, but the :before and :after pseudo-selectors just really don\'t look like they\'re gonna cut it here.
Speaking with regard to the spec (http://www.w3.org/TR/CSS2/zindex.html), since a.someSelector is positioned it creates a new stacking context that its children can\'t break out of. Leave a.someSelector unpositioned and then child a.someSelector:after may be positioned in the same context as a.someSelector.
Try it out
el {
transform-style: preserve-3d;
}
el:after {
transform: translateZ(-1px);
}
I know this question is ancient and has an accepted answer, but I found a better solution to the problem. I am posting it here so I don\'t create a duplicate question, and the solution is still available to others.
Switch the order of the elements. Use the :before
pseudo-element for the content that should be underneath, and adjust margins to compensate. The margin cleanup can be messy, but the desired z-index
will be preserved.
I\'ve tested this with IE8 and FF3.6 successfully.
Set the z-index
of the :before
or :after
pseudo element to -1 and give it a position
that honors the z-index
property (absolute
, relative
, or fixed
). This works because the pseudo element\'s z-index
is relative to its parent element, rather than <html>
, which is the default for other elements. Which makes sense because they are child elements of <html>
.
The problem I was having (that lead me to this question and the accepted answer above) was that I was trying to use a :after
pseudo element to get fancy with a background to an element with z-index
of 15, and even when set with a z-index
of 14, it was still being rendered on top of its parent. This is because, in that stacking context, it\'s parent has a z-index
of 0.
Hopefully that helps clarify a little what\'s going on.