Pseudo element on parent hidden behind child image on IE8 - css

Why in IE8, is the background color of a pesudo element flowing behind children of the parent? The text flows in front, but the background-color does not. Z-index did not seem to help any.
I haven't been able to determine if this is a bug in IE8 or not. It seems like this would have been a pretty common use-case, but I couldn't find many blog posts or SO questions related to it.
http://jsfiddle.net/VAg2E/
<div id="parent">
<img src="http://placehold.it/200x200">
</div>
#parent{ padding: 20px; }
#parent:before{
content: 'Behind the image';
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
background-color: red;
}
Edit : A related Stack Overflow Question about Stacking Order

This is definitely a bug in IE8; since your :before pseudo-element is positioned, it should create a new stacking context and always be drawn on top of the img unless you give it a negative z-index (even then, the entire element should be drawn behind it, not just its background).
This issue also seems specific to stacking between :before and :after pseudo-elements and replaced elements like img. It looks like IE8 is treating replaced content differently in terms of stacking, but whatever it is doing, it's definitely not conforming to the spec.
As you're probably aware, this is fixed in IE9.

Have your exact same issue, the only thing you can do is force the stacking order via CSS and z-index. The only catch is that z-index is placed on child element starting from parent element, so you wont be able to do a proper logic order as #parent-element {z-index: 2} and #child-element {z-index: 1}, the z-index for the #child-element will just be set to level 1 as a separate stack order inside the #parent-element.
You can still set z-index for the #child-element with a -1 value, it will just get back the whole #parent-element stacking order.
So to recap:
#parent-element { z-index: 99;} /* or any arbitrary number fitting */
#child-element {z-index: -1;}
Also remember to give both elements a position: relative/absolute to enable the stacking order fo z-index

IE8 only supports pseudos if <!DOCTYPE> is declared. Source
#parent { padding: 20px; z-index: 2; }
#parent:before {
content: 'Behind the image';
position: absolute;
top: 0;
left: 0;
width: 100px;
height: 100px;
background-color: red;
z-index: -1;
}​

Related

How is 'relative' positioning placing the tooltip at the correct position?

Here's an example of a CSS tooltip. The author positions the toolip relatively.
.tooltip{
display: inline;
position: relative;
}
However, the tutorial says,
Relative. This type of positioning is probably the most confusing and
misused. What it really means is "relative to itself". If you set
position: relative; on an element but no other positioning attributes
(top, left, bottom or right), it will no effect on it's positioning at
all, it will be exactly as it would be if you left it as position:
static; But if you DO give it some other positioning attribute, say,
top: 10px;, it will shift it's position 10 pixels DOWN from where it
would NORMALLY be. I'm sure you can imagine, the ability to shift an
element around based on it's regular position is pretty useful. I find
myself using this to line up form elements many times that have a
tendency to not want to line up how I want them to.
There are two
other things that happen when you set position: relative; on an
element that you should be aware of. One is that it introduces the
ability to use z-index on that element, which doesn't really work with
statically positioned elements. Even if you don't set a z-index value,
this element will now appear on top of any other statically positioned
element. You can't fight it by setting a higher z-index value on a
statically positioned element. The other thing that happens is it
limits the scope of absolutely positioned child elements. Any element
that is a child of the relatively positioned element can be absolutely
positioned within that block. This brings up some powerful
opportunities which I talk about here.
What I understand is that, without modifiers like top, left etc. relative is equivalent to static and goes with the flow of the page. Then how's the tooltip being displayed at the correct position, i.e. above the hyperlink? Shouldn't it appear at the end of the page instead?
The CSS you provided for tooltip is not complete. I think you saw it in w3schools. But note that there are two elements for it: a parent element with .tooltip class and a child element (actual tooltip text) inside it with .tooltiptext class.
the parent element has position: relative without any top, left ... positions which acts as you said as a static element in its original (normal) place. But the child tooltiptext inside it has a position: absolute which is why it is seperated from normal text flow and put over them.
Here is a sample:
.tooltip {
/* this is just to add meaning for position:absolute of .tooltiptext */
position: relative;
color: navy;
}
.tooltip .tooltiptext {
/* Position the tooltip */
position: absolute;
z-index: 1;
top: 100%;
left: 10%;
/* style the tooltip */
min-width: 50px;
background-color: #ff9;
color: black;
font-size: 10pt;
border-radius: 3px;
padding: 3px 10px 6px;
white-space: nowrap;
visibility: hidden;
}
.tooltip:hover .tooltiptext {
visibility: visible;
}
<span>Sample: </span>
<span class="tooltip">Hover over me
<span class="tooltiptext">Tooltip text</span>
</span>

css property will-change undefined behaviour

I am using semantic-ui, and have managed to narrow down some undefined behaviour in the css property will-change (I found it in their modal's):
.outer{
background-color: black;
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
}
.inner{
position:absolute;
background-color: white;
left: 50%;
top: 100px;
width: 400px;
margin-left: -200px;
height: 100px;
padding: 5px;
/**
* comment out the line below
* to see the desired/different result
**/
will-change: transform;
}
.baby{
color: yellow;
position: fixed;
left: 20px;
top: 20px;
right: 0;
border: 1px solid red;
}
<div class="outer">
<div class="inner">
<div class="baby">here</div>
<div class="content">some content</div>
</div>
</div>
I have only tested this in chrome. Does anyone have more information on what is going on here? Why does will-change do anything to the actual layout?
will-change affects layout because it's often used with properties whose values can change between one that doesn't affect layout, and one that does. Setting will-change tells the browser to prepare for such a potential change, which results in the browser applying the layout changes in advance.
This isn't undefined behavior:
If any non-initial value of a property would create a stacking context on the element, specifying that property in will-change must create a stacking context on the element.
If any non-initial value of a property would cause the element to generate a containing block for absolutely positioned elements, specifying that property in will-change must cause the element to generate a containing block for absolutely positioned elements.
If any non-initial value of a property would cause the element to generate a containing block for fixed positioned elements, specifying that property in will-change must cause the element to generate a containing block for fixed positioned elements.
If any non-initial value of a property would cause rendering differences on the element (such as using a different anti-aliasing strategy for text), the user agent should use that alternate rendering when the property is specified in will-change, to avoid sudden rendering differences when the property is eventually changed.
For example, setting opacity to any value other than 1 creates a stacking context on the element. Thus, setting will-change: opacity also creates a stacking context, even if opacity is currently still equal to 1.
In your case, since transforms result in the creation of both a stacking context and a containing block, setting will-change: transform will therefore also result in the creation of a stacking context and a containing block, because you're suggesting to the browser that the element might have a transform either now or later, and when it does, the layout will be affected.

Override CSS Z-Index Stacking Context

I'm trying to override / ignore the stacking context for an element so it can be positioned on the z-axis relative to the page root.
However, according to the article What No One Told You About Z-Index:
If an element is contained in a stacking context at the bottom of the stacking order, there is no way to get it to appear in front of another element in a different stacking context that is higher in the stacking order, even with a z-index of a billion!
New stacking contexts can be formed on an element in one of three ways:
When an element is the root element of a document (the element)
When an element has a position value other than static and a z-index value other than auto
When an element has an opacity value less than 1
With the following example:
.red, .green, .blue { position: absolute; }
.red { background: red; }
.green { background: green; }
.blue { background: blue; }
<div><span class="red">Red</span></div>
<div><span class="green">Green</span></div>
<div><span class="blue">Blue</span></div>
If the first div is given opacity:.99;, (which creates a new stacking context on the first node) then even if .red has z-index:1, it will still be placed behind the other elements because it is just rendered as the highest element within that stack.
Working Demo in jsFiddle
Which looks like this:
Q: Is there a way for an element to ignore the stack context of any of it's parent elements and ask to be positioned relative to the original stack context of the page?
Q: Is there a way for an element to ignore the stack context of any of it's parent elements and ask to be positioned relative to the original stack context of the page?
No, it's not possible to transfer a positioned element between stacking contexts without repositioning the element in the DOM. You cannot even move an element to the root stacking context by using position: fixed or position: absolute (as you have observed, .red is being positioned relative to its parent, div:first-child because it creates a new stacking context).
That being said, given your HTML and CSS it should be trivial to just reassign the classes to the div elements instead, as shown in other answers and here so all your divs and spans participate in the root stacking context:
<div class="red"><span>Red</span></div>
<div class="green"><span>Green</span></div>
<div class="blue"><span>Blue</span></div>
But your situation probably isn't as simple as it seems.
We can do it using 3D transformation and we will be able to bring any element to the front even if it's trapped inside a stacking context:
.red,
.green,
.blue {
position: absolute;
width: 100px;
color: white;
line-height: 100px;
text-align: center;
}
body,
div:first-child {
transform-style: preserve-3d; /* this is important for the trick to work */
}
.red {
top: 20px;
left: 20px;
background: red;
/*z-index: 1; we no more need this */
transform:translateZ(1px); /* this will do the trick */
}
.green {
top: 60px;
left: 60px;
background: green;
}
.blue {
top: 100px;
left: 100px;
background: blue;
}
<div><span class="red">Red</span></div>
<div><span class="green">Green</span></div>
<div><span class="blue">Blue</span></div>
More details and examples here: Why can't an element with a z-index value cover its child?
As it stated in the The stacking context: "Using z-index, the rendering order of certain elements is influenced by their z-index value. This occurs because these elements have special properties which cause them to form a stacking context.
To partly overcome stacking content problem you can use css properties to display unwanted elements:
opacity: 0.1;
or
display: none;

Is it possible to set the stacking order of pseudo-elements below their parent element? [duplicate]

This question already has answers here:
How to get a child element to show behind (lower z-index) than its parent? [duplicate]
(7 answers)
Why can't an element with a z-index value cover its child?
(5 answers)
Closed 3 years ago.
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;
}
#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>
Try it out
el {
transform-style: preserve-3d;
}
el:after {
transform: translateZ(-1px);
}
There are two issues are at play here:
The CSS 2.1 specification states that "The :beforeand :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.
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.
I fixed it very simple:
.parent {
position: relative;
z-index: 1;
}
.child {
position: absolute;
z-index: -1;
}
What this does is stack the parent at z-index: 1, which gives the child room to 'end up' at z-index: 0 since other dom elements 'exist' on z-index: 0. If we don't give the parent an z-index of 1 the child will end up below the other dom elements and thus will not be visible.
This also works for pseudo elements like :after
I don't know if someone will have the same issue with this. The selected answer is partially correct.
What you need to have is:
parent{
z-index: 1;
}
child{
position:relative;
backgr

Why is my position absolute child placed relative to the browser window instead of its position relative parent?

I have these two divs, one inside another, and I have the styles defined. The encapsulating one is relative and the child is absolute.
Isn't the child supposed to be positioned according to the left top corner of the outer div, #RightSection?
Instead, it's doing it according to the browser window, any leads?
<div id="RightSection">
<div id="Panels">
</div>
</div>
#RightSection
{
position: relative;
}
#Panels
{
position: absolute;
background-color: Blue;
width: 100px;
height: 100px;
z-index: 9000;
}
I have also found that if I do not declare the top and left css parameters for absolutely positioned elements it seems to ignore a parent above it and just jump to the body of the page.
Try just giving it top and left parameters, see if it helps,
#Panels
{
position: absolute;
top: 0;
left: 0;
background-color: Blue;
width: 100px;
height: 100px;
z-index: 9000;
}
It should look just fine once you add in those default parameters.
Absolute positioning inside of relative positioned elements is supposed to do what you describe, but it's not always supported behaviour. What browser are you use and what DTD are you serving?
See http://www.brainjar.com/css/positioning/default4.asp for details. It also has a demo of the positioning so that you can verify it works or not in your browser.
I can confirm that this does not work in IE6. I can't vouch for other browsers while I'm at work, though. Brief searching online leads me to believe that this problem exists in IE7 too, and would conceivably be an issue in IE8 as long as it's rendering in IE7 mode.

Resources