opacity value less than 1 and stacking without z-index - css

MDN - Stacking without z-index states that when no element in a page has a z-index, elements are stacked in this order:
Background and borders of the root element
Descendant blocks in the normal flow, in order of appearance (in HTML)
Descendant positioned elements, in order of appearance (in HTML)
But that seems not the case when an element of opacity less than 1 is involved:
http://jsfiddle.net/pbQfY/2/
Is it safe to assume that the real order is the following?
Background and borders of the root element
Descendant blocks in the normal flow, in order of appearance (in HTML)
Descendant positioned elements and descendant elements that create stacking context, in order of appearance (in HTML)

Looks like that MDN article is just the basic version of the actual stacking contexts explanation, which is also touched on in the visual formatting module. However, this particular gotcha is from the CSS color module (emphasis mine):
Since an element with opacity less than 1 is composited from a single
offscreen image, content outside of it cannot be layered in z-order
between pieces of content inside of it. For the same reason,
implementations must create a new stacking context for any element
with opacity less than 1. If an element with opacity less than 1 is
not positioned, implementations must paint the layer it creates,
within its parent stacking context, at the same stacking order that
would be used if it were a positioned element with ‘z-index: 0’ and
‘opacity: 1’. If an element with opacity less than 1 is positioned,
the ‘z-index’ property applies as described in [CSS21], except that
‘auto’ is treated as ‘0’ since a new stacking context is always
created. See section 9.9 and Appendix E of [CSS21] for more
information on stacking contexts. The rules in this paragraph do not
apply to SVG elements, since SVG has its own rendering model ([SVG11],
Chapter 3).

Related

Avoid z-index working relative to the parent element

I come with a question about an odd behavior regarding the z-index property. The situation in terms or layers is the following:
div#wrapper
div#sidebar (fixed position and 5 as z-index)
div#pop-up (absolute position and 15 as z-index)
div#black-layer (fixed position and 10 as z-index)
The thing then is that I want to have a semi-transparent black layer over everything, with the next exception: over it I want another arbitrary div (depending on the case). A bit like the typical light-box.
What's happening now is that the pop-up, which is supposed to be over the black-layer, since their z-index is higher, is actually under it.
My conclusion after several tries is that the reason this occurs like so is because #pop-up is a child of #sidebar. Indeed, if I put it outside, it works as I pretend. Like:
div#wrapper
div#sidebar
div#pop-up
div#black-layer
But this is not a good solution at all. First because it is not semantically correct from the point of view of the HTML. And also because I have the necessity of having more "pop-ups" in other parts of the code and is not a good idea split the logic this way by keeping separately all of them.
Thank you in advance.
Update: It is even more strange now. I haven't changed anything, but just made a test in Firefox instead of Chrome, and it works there as I expected, so the pop-up is in fact over the black-layer. And also in Opera. And it does not work in Maxthon. Just as a note, I'm using Linux.
What's happening now is that the pop-up, which is supposed to be over the black-layer, since their z-index is higher, is actually under it.
As it perfectly well should be. z-index is perfectly well defined, for example in this part of the spec:
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.
The root element forms the root stacking context. Other stacking
contexts are generated by any positioned element (including relatively
positioned elements) having a computed value of 'z-index' other than
'auto'. Stacking contexts are not necessarily related to containing
blocks.
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).
You are incorrectly assuming z-indexes are shared amongst the entire document, while they are only valid within their own stacking context, which is actually created for every z-indexed element - therefore your #popup is the highest element in #sidebar, but both are stacked underneath #black-layer as it is higher in the root stacking context. Older versions of IE (in quirks mode) actually used the model you are expecting, but that was fixed later on.
So, you'll need to move some elements around. Semantically, that doesn't matter at all since you'll be needing JS anyway to clone/generate the popups in practice.

How does a web browser determine the z-index if the style is not explicitly defined

I am really curious. You can obtain the z-index from an element but If a page is "just built" without a definition of z-indices, how would that resolve. How does the browser do it? Can we access this via javascript to obtain the browsers definition of the z-index instead of using the computer style component?
Why am i asking? Well, style returns AUTO a loot, but i am curious as to what "auto" is according to the browser etc.
How does the browser do it?
It simply follows the CSS spec as described in section 9.9. In particular:
auto
The stack level of the generated box in the current stacking context is 0. The box does not establish a new stacking context unless it is the root element.
And:
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.
As for how to actually obtain the stack level for a given element, I don't think the DOM exposes this information because it's more of a CSS implementation detail than anything else (plus it would be zero anyway for all non-positioned elements with auto z-index, because it is a relative value and not an absolute one). And as already mentioned this information is not available through getComputedStyle() either.
There is a natural stacking order that the browser use to determine how elements stack
Below is a list showing the order that items fit into a stacking
context, starting with the bottom of the stack. This list assumes none
of the items has z-index applied:
Background and borders of the element that establish stacking context
Elements with negative stacking contexts, in order of appearance
Non-positioned, non-floated, block-level elements, in order of
appearance
Non-positioned, floated elements, in order of appearance
Inline elements, in order of appearance
Positioned elements, in order
of appearance
For more information check out: http://coding.smashingmagazine.com/2009/09/15/the-z-index-css-property-a-comprehensive-look/

In CSS 2.1, if a parent establish a stacking context, why can the children's text go under the parent but the background color cannot?

This is an advanced CSS question.
In the JSFiddle: (as tested on Chrome 26.0, Firefox 20.0, and IE 10)
http://jsfiddle.net/4yRrm/10
The parent establishes a stacking context, and the children have higher z-index than the parent and cover the parent up, so that's all fine.
But what about in http://jsfiddle.net/4yRrm/11
Now the children have a lower z-index than the parent. The text of the children now go under that parent's text (as you can see the parent's text in blue color covering up the black color of the children's text), but why do the children's background color go above the parent instead? Please substantiate your answer with the spec. Why is there such a behavior -- does that achieve a certain purpose?
As it is, the background of the parent is the lowest layer, and then the children's background, and then the children's text, and then the parent's text. So the parent's painting are at the "extreme end" -- the background as the lowest layer, and the text as the topmost layer, and the children's content are "sandwiched" inside these two extremes.
And related is: how do you make the parent go above the children completely even for the backgrounds, when the parent establishes a stacking context? Please do not answer to remove the positive: relative or to remove the z-index: 0 of the parent, as that will fail to establish a stacking context for the children. That is, the parents MUST have a position of either relative, absolute, or fixed, and at the same time, have a z-index of an integer (and cannot be auto).
CSS2.1 states:
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).
As you can see from items 1 and 2, the child stacking contexts with negative stack levels (i.e. your child elements) are always painted above the background of the current stacking context (i.e. your parent element).
The text of the parent element is then painted above the child elements, as in item 5.
It is not possible to make a stacking context sit completely above any of its descendants — its background and borders will always be painted at the very bottom no matter what you do. Since a box may only appear in one stacking context at a time (stacking contexts can be nested but that's not relevant here), you'll have to move those elements out of the parent stacking context if you want them to sit completely under the parent, while allowing the parent to establish its own stacking context for its other contents. For example, you can move them just outside the parent such that they become siblings instead, sharing the same stacking context which in your case is the root stacking context.
Very interesting question:
Why is there such a behavior?
Based on the definitions,
http://www.w3.org/TR/CSS21/visuren.html#z-index
and
http://www.w3.org/TR/CSS21/zindex.html
If you follow the steps, it gets rendered as it is defined.
(Image from http://www.vanseodesign.com/css/css-stack-z-index/)
Within each stacking context, the following layers are painted in
back-to-front order:
1- the background and borders of the element forming the stacking context.
2- the child stacking contexts with negative stack levels (most negative first).
3- the in-flow, non-inline-level, non-positioned descendants.
4- the non-positioned floats.
5- the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
6- the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
7- the child stacking contexts with positive stack levels (least positive first).
How do you make the parent go above the children completely even for the backgrounds, when the parent establishes a stacking context?
If a standard browser is following the definition, then you can't do that for a stacking context and its children, because that would be in conflict with the definition.
Your text node :
Hello Chip Hello Chip Hello Chip Hello Chip
also gains a stacking context :
#chip01 : imaginary-stack-context: 0
#chip01 "Hello Chip..." - imaginary-stack-context: 1
#chip02 - imaginary-stack-context: 0
#chip03 - imaginary-stack-context: 0 ( since you have z-index: -1 makes it behind all other elements with positive / auto z-indexes. )
The CSS 2.1 specs were given already by #BoltClock.

possible to set z-index rules which only affect child elements of a certain div?

Is it possible to set z-index that only applies to a certain 'scope', such as only affecting children of a certain element.
I've got an containerDiv with z-index 0. It contains a bunch of circles which should be placed on top of eachother in various depths, but I don't want them to affect any other elements on the page.
I've got a bunch of other elements on the page (popups, dropdowns etc) which have z-index 1, and I would like them to be placed on top of the containerDiv and all of it's childelements.
Since I'm lazy I'd preferably want to avoid having to adjust these element's z-index values based on the circle with the highest z-index...
Much be awesome if there was some way that all other elements could view the containerDiv and all it's children as having the same z-index.
Is this possible to achieve with css?
The answer depends on whether or not your other elements are descendants of the containerDiv or not. To answer the question: Yes, it's almost certainly possible, given a bit of shuffling of the markup.
But what you need to understand is the concept of stacking context:
http://www.w3.org/TR/CSS2/visuren.html#layers
Stacking context is not inherited the way other properties are: "A stacking context is atomic from the point of view of its parent stacking context; boxes in other stacking contexts may not come between any of its boxes." It's not like every element on the page with z-index:2 will be behind everything on the page with z-index:4. Z-index (combined with a position declaration) is typically (though not exclusively) used to resolve the stacking order when two elements share a containing element.

Z-index: How to make nested elements appear underneath their parent element

This fiddle should demonstrate the issue:
http://jsfiddle.net/5sqxQ/2/
I want the sub menu to appear underneath the parent menu. I was then was looking to extend this with JavaScript to slide the menu from underneath on hover of the parent li element.
Not fussed about the JavaScript but can't figure out how to style the elements to achieve the desired layering.
It doesn't work because you are applying a z-index to the parent element which makes the child element stack relative to the other elements within the parent.
Once you assign an element a value for
z-index (other than auto), that
element establishes its own local
stacking context. This means that all
of the element's descendants have
their own stacking order, relative to
the ancestor element.
So if the parent has z-index: 9 and the child is z-index: 8, it's kind of like assigning a z-index of 9, 8
See the article here for a better explanation.
If you remove the z-index on the parent and set the sibling element to z-index: -1, that should work. I'm not sure about all browsers, but it works in Chrome anyway.
Here is the updated fiddle
Hope that helps.
You don't.
Instead, make the a be the "Sign In" "button".
Something like this: http://jsfiddle.net/5sqxQ/15/
Try setting the parent and siblings containers position to relative.
Its worked for me before.
Look at the rules below for how elements are stacked and you can easily come up with your own solution.
ex. Like thirtydot said, give "Sign In" .users > li > a a position, relative or absolute, and z-index: 1
The Stacking order and stacking context rules below are from this link
Stacking Order within a Stacking Context
The order of elements:
The stacking context’s root element (the <html> element is the only stacking context by default, but any element can be a root element for a stacking context, see rules below)
You cannot put a child element behind a root stacking context element
Positioned elements (and their children) with negative z-index values (higher values are stacked in front of lower values; elements with the same value are stacked according to appearance in the HTML)
Non-positioned elements (ordered by appearance in the HTML)
Positioned elements (and their children) with a z-index value of auto (ordered by appearance in the HTML)
Positioned elements (and their children) with positive z-index values (higher values are stacked in front of lower values; elements with the same value are stacked according to appearance in the HTML)
When a Stacking Context is Formed
When an element is the root element of a document (the <html> 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
Several newer CSS properties also create stacking contexts. These include: transforms, filters, css-regions, paged media, and possibly others. See https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context
As a general rule, it seems that if a CSS property requires rendering in an offscreen context, it must create a new stacking context.

Resources