What has bigger priority: opacity or z-index in browsers? - css

I'm coding a "popup window" in JavaScript and I've come across an interesting thing:
The navy square under the popup window is visible even though I would expect it to be hidden. The popup was added after the square, so it should be on the top.
CSS opacity property of the navy square is 0.3. From what I've tried, it seems that every number from the interval (0,1) would yield the same result. If I change it to 1, then it behaves as expected (i.e. the part of the square under the popup is hidden).
I've tried to set the z-index property to 10 for the square and 100 for the popup, but it doesn't change anything.
What am I missing? Why is part of square displayed?
Tested browsers:
Firefox 3.6.x
Chrome 4

This is not a bug and is actually how it's supposed to work. It's a bit confusing as the elaborate description of Stacking Contexts doesn't mention anything about it. However, the visual formatting module links to the color module where this particular gotcha can be found (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).

It's not a problem of opacity being more important than z-index, rather than z-index being relative to their stacking context (see z-index in the CSS2 specification).
In other words, z-index are only significant within the context of a positioned ancestor (whether its relative, absolute or fixed). What you need to do to fix your problem is add a position: relative; to the element that contain both your popup and your navy square, and probably add it a z-index: 1; . Seeing your screenshot it will probably be a top element such as a wrapper div.

Workaround for two elements, like divs: add a 0.99 opacity to your top element, and the order of both is reestablished.
opacity: 0.99;

An alternative to using opacity, is to use a transparent colour (with an alpha value)
So, rather than using
{
background: gray;
opacity: 0.5;
}
You could try
{
background: rgba(128,128,128,0.5);
}
It isn't identical, but I was encountering the same issue you were having, and the above fixed it.

Example code might be needed to debug this problem.
You might put overflow: hidden and possibly position: relative in a DIV which surrounds all the editor objects to try to force the elements to only be drawn within that DIV, e.g:
<div style="overflow: hidden; position: relative">
(Editor object buttons go here)
</div>
As a last resort, you could also try a iframe in between the two elements to try to stop them seeping through.

You might try to set the popup window's DIV like this using !important so the style doesn't change on applying new style or class:
background-color: white !important;
z-index: 100 !important;
opacity: 1.0 !important;
Then, make new CSS class:
.PopupElement
{
z-index: inherited;
opacity: inherited;
}
And add class to all elements in the window, like this for example:
<input value="posx" class="some_class PopupElement"/>
My guess is that this would work, since there is no priority in applying CSS attributes... as far as I know. =)

I had the same issue. Using rgba instead of color/opacity solved my problem. Working with LESS (in the Bootstrap framework), the fade() function did the conversion for me.

Although #Guillaume Esquevin already gave a great answer, I will try to expand on it in case someone ignores what a stacking context is (like I did).
As you can read here, there is something called stacking context, which refers to a group of elements sharing a parent that move together in the stack. An example could be a div and all its children.
There are three ways to create a stacking context: in the root of the document (the html element), by positioning the parent element, and by changing the opacity of the parent to something lower than 1.
Then, if you have a div with opacity lower than 1 and you want some sibling element of this div to appear behind it (and its children), you can create a new stacking context on such sibling by setting its position to relative or by changing its opacity as well.

Related

will-change breaks showing position absolute div on :hover

I have an issue with will-change. I have no idea why it causes this problem but when I add will-change on wrapper in which I have list with hidden divs (which should show up on hover) it breaks showing that divs. t shows part of it or not at all (depends on browser). Do you have any idea why it breaks that functionality?
Link -> http://jsbin.com/rukanajugi/1/edit?html,css,output
Contrary to common belief, the will-change property may actually have an impact on the visual appearance of the element, as it creates a new CSS Stacking Context if used with Stacking Context Creating Properties (e.g. position, opacity, transform) BEFORE the actual transformation was made.
This may therefore change the layout, as the order of the layers (which element is above which one) may be changed.
In your case, the creation of the new Stacking Context through will-change: opacity, causes the layout issue. The hidden divs are positioned absolute, therefore don't increase the size of their parents/grandparents and are therefore cropped by the .menu-wrapper, which now has a stacking context.
You have multiple solutions for this, e.g.
Use .menu-wrapper { overflow: visible; }
Increase the Size like this: .menu-wrapper { height: 200px; }
Do not use Stacking Context creating properties on the will-changeattribute. E.g. using .menu-wrapper { will-change: border-width; } won't create any Stacking Context. As Soon as your .menu-wrapper gets properties, which create a Stacking Context (e.g. opacity: 0.9999), it will break again, however.

css opacity affecting sibling image opacity

I have a simple div with two children, a div with an image and yet another div as below:
<div style="width: 500px;">
<div class="settingicon righty">
<img src="/images/icons/setting.png" />
</div>
<div class="schedulepicker quat todaytoday">MONDAY</div>
</div>
I wanted so that when the second div is hovered, it reduces its opacity to 0.9, so in my CSS my .schedulpicker has this rule:
.schedulepicker:hover {
opacity: 0.9;
}
The problem is when it is hovered, the sibling image changes in opacity as well. Why is this so?
EDIT
Here's a fiddle
http://jsfiddle.net/VUzg9/4/
i am starting to wonder could it actually be the file itself.
EDIT 2
tested with jpg and gif, probably not the image issue.
You need to set the position (default is static) and a z-index for your image.
See jsfiddle
.righty {
float: right;
position: relative;
z-index: 100;
}
The opacity you're setting on #schedulepicker is creating a new stacking context, and stacking contexts affect z-indexes. Since you didn't specify z-indexes manually, they're being auto assigned, and #schedulepicker has a higher value than #settingicon because it comes later in the markup.
EDIT
The W3C color module says the following:
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’.
Great question - it looks like a bug.
You need to put a position and a z-index on it in order to get it to work.
.righty {
float: right;
position: relative;
z-index: 1;
}
http://jsfiddle.net/VUzg9/9/
EDIT
I want to add to this answer because it's a very intriguing problem.
If we look at the spec it tells us that:
In future levels of CSS, other properties may introduce stacking contexts,
for example 'opacity' [CSS3COLOR].
As #enfredH04 pointed out in his answer, as soon as the element changes opacity, it appears to then gain a stacking context (maybe Blink implemented a part of the spec [quoted above] that has not actually been written, or at least published, yet?) It's sibling does not have it's own stacking context and, thus, appears behind the element that changes opacity.
You can see this if you give the element a starting opacity of 0.9 - http://jsfiddle.net/VUzg9/11/ - at this point it must gain a stacking context. (Interestingly a starting opacity of 1 does not give it a stacking context).
It's not changing the opacity of the "sibling", it's actually covering it up on-hover.
See two contrasting examples: jsfiddle
Setting position: relative and a z-index seem to solve the issue

Why does opacity negate pointer events?

In the following setup, why does the click event (and any other pointer event) not get fired?
If you remove the opacity: 0.5 line, it will work fine.
http://jsfiddle.net/523ve/
For posterity, in case jsFiddle ever goes down (December 21 is approaching):
HTML:
<div>
<a>Click</a>
<p>Paragraph</p>
</div>
CSS:
div { position: relative; margin: 40px; }
a { position: absolute; top: 0; right: 0; }
p { opacity: 0.5; }
JS:
$(document).ready(function(event) {
$("a").click(function(event) {
alert("Alert");
});
});
(Tested in latest stable Chrome and Firefox)
"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..."
http://www.w3.org/TR/css3-color/#transparency
EDIT:
Also, your particular example has the <p> element overlapping the <a>.
http://jsfiddle.net/523ve/4/
So you could fix this by either moving the <a> so that it does not interfere, or by using z-index to re-adjust the stacking order. The latter option may have cross-browser issues but I have not tested. I recommend re-factoring your HTML so that these two elements do not overlap with each other.
EDIT 2:
Here is a related SO question, however the accepted answer is incorrect.
What has bigger priority: opacity or z-index in browsers?
you might understand by this line
The opacity CSS property specifies the transparency of an element, that is, the degree to which the background behind the element is overlaid.
Using this property with a value different than 1 places the element in a new stacking context.
source :MDN
and here p is overlapping a so either set the width of p to not overlap a or set a higher z-index
The a element comes before p, and note that p is 100% wide. This means that p is effectively ABOVE a.
You can either change a element's z-index to something above 0 (http://jsfiddle.net/523ve/5/) or swap p and a in your HTML so that a comes after p (http://jsfiddle.net/523ve/3/).
I hope what I've written makes any sense ;).

CSS transform vs position

Can some please explain to me the difference in transitioning the positional left or right properties or the -transform: translateX(n), as the both seem to achieve the same thing yet can be applied independently. I understand about the possibility of hardware acceleration but that's dependent on implementation.
// psuedo code;
#box {
-transition-property: all;
-transition-duration: 1s;
}
// javascript
box.style.transform = "translateX(200px)";
vs
box.style.left = "200px";
What's the advantage of one over the other?
Thanks,
p
The drawing order of rendering layers is:
layout layer
paint layer
compositor layer
A redraw in a layer will trigger redraw in subsequent layers.
Changing left or margin will trigger a redraw in layout layer (which, in turn, will trigger redraws in the other two layers) for the animated element and for subsequent elements in DOM.
Changing transform will trigger a redraw in compositor layer only for the animated element (subsequent elements in DOM will not be redrawn).
The difference in performance (hence in frames per second or, in simple terms, in animation smoothness) is tremendous. Using the first technique will often result in jittery animations even on good machines (when the processor is busy), while the second will likely run smoothly even on systems with limited resources.
Another advantage of using transforms is compositor redraws are heavily optimized (animations to multiple elements result in one redraw for all), while changing layout layer will trigger a redraw after each change of each element.
For a more detailed explanation on rendering techniques and rendering performance I recommend Google's Web Fundamentals.
Position is dependant on what the position is set to, transform works from the element itself. So you could see transform as being identical to position:relative;.
However, you can still use transform on an absolutely positioned element (to position it relatively without needing an additional element or resorting to margins), as well as transform being CSS3 so if you can use position instead you should.
top and left CSS properties work only on elements positioned relative, absolute or fixed. Also, top and left properties rely on the parent's position (relative it, absolute or static). Translations are not affected by that settings.
Translation transformations are "identical" to applying top and left when element has position: relative. In any other case they aren't the same operations.
As mention above:
position:relative and translate can achieve the same effect in a different way
position:relative happen in the layout phase which means it can interact with other elements in terms of layout
while translate happens when all the layout process complete, further it even already painted, what is remaining is a matter where to put the element, so it has no interaction with the existing layout
consider the following example which will present an obvious visual difference by using the two methods
.container {
width: 300px;
height: 300px;
overflow: scroll;
background: red;
}
.child {
width: 280px;
height: 280px;
background: green;
}
<div class="container">
<div class="child"></div>
</div>
By setting position:relative;top:100px to the child element, the container has no enough space to hold the child, and because of the fact that overflow is set as scroll, the scroll bar will present
On the other hand, By setting transform:translateY(100px), it has nothing to do with the layout, so the scrollbar will not present
Like the spec said:
However, if relative positioning causes an 'overflow:auto' or
'overflow:scroll' box to have overflow, the UA must allow the user to
access this content (at its offset position), which, through the
creation of scrollbars, may affect layout
To conclude, position is involved in layout, while transform not, which means transform can have better performance.
prefer transform to position when the layout is not your concern

IE 6 & IE 7 Z-Index Problem

http://madisonlane.businesscatalyst.com
I'm trying to get the div#sign-post to sit above the div#bottom. This works fine in all browsers except IE6 & IE7. Can anyone see what the problem is here?
Also IE6 is displaying an additional 198px to the top of div#bottom.
Most of the answers here are wrong; some work, but not for the reason they state. Here is some explanation.
This is how z-index should work according to the spec:
you can give a z-index value to any element; if you don't, it defaults to auto
positioned elements (that is, elements with a position attribute different from the default static) with a z-index different from auto create a new stacking context. Stacking contexts are the "units" of overlapping; one stacking context is either completely above the another (that is, every element of the first is above any element of the second) or completely below it.
inside the same stacking context, the stack level of the elements is compared. Elements with an explicit z-index value have that value as a stack level, other elements inherit from their parents. The element with the higher stack level is displayed on top. When two elements have the same stack level, generally the one which is later in the DOM tree is painted on top. (More complicated rules apply if they have a different position attribute.)
In other words, when two elements have z-index set, in order to decide which will show on top, you need to check if they have any positioned parents which also have z-index set. If they don't, or the parents are common, the one with the higher z-index wins. If they do, you need to compare the parents, and the z-index of the children is irrelevant.
So the z-index decides how the element is placed compared to other children of its "stacking parent" (the closest ancestor with a z-index set and a position of relative, absolute or fixed), but it doesn't matter when comparing to other elements; it is the stacking parent's z-index (or possibly the z-index of the stacking parent's stacking parent, et cetera) which counts. In a typical document where you use z-index only on a few elements like dropdown menus and popups, none of which contains the other, the stacking parent of all the elements which have a z-index is the whole document, and you can usually get away with thinking of the z-index as a global, document-level ordering.
The fundamental difference with IE6/7 is that positioned elements start new stacking contexts, whether they have z-index set or not. Since the elements which you would instinctively assign z-index values to are typically absolutely positioned and have a relatively positioned parent or close ancestor, this will mean that your z-index-ed elements won't be compared at all, instead their positioned ancestors will - and since those have no z-index set, document order will prevail.
As a workaround, you need to find out which ancestors are actually compared, and assign some z-index to them to restore the order you want (which will usually be reverse document order). Usually this is done by javascript - for a dropdown menu, you can walk through the menu containers or parent menu items, and assign them a z-index of 1000, 999, 998 and so on. Another method: when a popup or dropdown menu becomes visible, find all its relatively positioned ancestors, and give them an on-top class which has a very high z-index; when it becomes invisible again, remove the classes.
Agree with validator comment - validating usually helps. But, if it doesn't heres a few pointers for z-index in IE:
1) elements who's z-index you're manipulating should be on the same level ie. you should be setting the z-index of #bottom and #body
if this is not feasible then
2) IE sometimes wont apply the z-index correctly unless the elements ou are applying it to have a position:relative. Try applying that property to #bottom and #body (or #signpost)
let me know how that works out
Darko
I just had this problem and the fix I found (thanks to Quirksmode) was to give the direct parent of the node you are trying to set a z-index of it's own z-index that is at less than the z-index of the node you are trying to set. Here is a quick example that should work in IE6
<html>
<head>
<style type="text/css">
#AlwaysOnTop {
background-color: red;
color: white;
width: 300px;
position: fixed;
top: 0;
z-index: 2;
}
#Header {
color: white;
width: 100%;
text-align: center;
z-index: 1;
}
</style>
</head>
<body>
<div id="Header">
<div id="AlwaysOnTop">This will always be on top</div>
</div>
<div id="Content">Some long amount of text to produce a scroll bar</div>
</body>
</html>
Welcome, I solved the problem with:
.header {
position: relative;
z-index: 1001;
}
.content {
position: relative;
z-index: 1000;
}
Looks to me like you have some malformed HTML in there. I tried counting, and perhaps I lost count of the opening and closing tags, but it looks like div#container isn't closed. Try running your page through a validator (such as W3C's HTML Validator, or something) and fixing some of the errors. That's helped me with these sorts of problems in the past. Good luck!
I've recently had an ongoing problem displaying one layer above another. In my case I was programmatically creating two layers in Javascript, one for diaplaying a custom control and one for creating a full screen layer behind it. FF was fine, bu IE displayed the full screen layer always on top of everything else.
After numerous trawls over the interweb, trying everyone's suggestions, the only way I eventually get it working was to remove position: attributes from both layers, and tweak the margin-top: attribute until I got a satisfactory result.
A bit of a hash, but it works and it'll be fine until IE 8 sorts out all of the current bugs......
the only reliable solution is, to put the top elements below in the code and then push them over the other stuff with absolute positioning.
e.g. Wordpress:
put the navigation in the footer file, but still inside the page wrapper.
might also bring some advantages for search engines, because they can directly start with the content, without crawling through the menu first...
UPDATE:
I need to correct myself. While putting the element below and then pushing it over is still the easiest way, there are certain cases when this is not possible in reasonable time. Then you have to make sure that each and every parent element has some kind of positioning and some senseful z-index. Then the z-index should work again even in IE7.

Resources