3

I have found a really strange behaviour for the CSS opacity combined with floating elements.
Consider following HTML:

<div style="position: relative; clear: both">
   <div style="float:left>Left button</div> 
   <div style="float:right>Right button</div>  
</div>
<div style="opacity: 0.9">Overlay</div>

The last div will overlay the first two floating ones. Removing the opacity will put the latest div under the floating ones.

This is how it looks on my real-life page (red background is just used to emphasize the effect): div with opacity Now, if I remove the opacity of the middle div: opacity disabled Sudenly, the floating divs are acessible.

I tried the z-index property, but wasn't surprised when this didn't help. I even achieved to reproduce this in JS fiddle.

So, what's this? Any workarounds?
Note: so far, tested in chrome and firefox. The result was the same.
Opera confirmed too.

PS.: Could anyone explain to me, why JSFiddle does not work in full-screen result? I think this is not the first time full screen result didn't work for me.

Tomáš Zato
  • 50,171
  • 52
  • 268
  • 778
  • Did you finish reading the question? I tested this in jsFiddle before even posting the question. And I added link of course. – Tomáš Zato Feb 19 '14 at 09:35
  • Here's updated link with nicer example (I updated it in question too). http://jsfiddle.net/Darker/K2nmL/1/ – Tomáš Zato Feb 19 '14 at 09:38
  • 2
    This looks relevant: http://stackoverflow.com/questions/2837057/what-has-bigger-priority-opacity-or-z-index-in-browsers – Turnip Feb 19 '14 at 09:39

2 Answers2

2

The problem is understanding stacking contexts and how they're rendered in the browser.

  • the root element (HTML),
  • positioned (absolutely or relatively) with a z-index value other than "auto",
  • elements with an opacity value less than 1.
  • on mobile WebKit and Chrome 22+, position: fixed always creates a new stacking context, even when z-index is "auto"

9.9.1 Specifying the stack level: the 'z-index' property

  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). Blockquote

When you apply an opacity change to the div, it creates a new stacking context. This means it creates a new stacking context that gets rendered later on (read: on top of stacks with lower levels).

There are different solutions depending on the effect you're trying to achieve, here's an example of how you can avoid the opacity issue entirely by using rgba values instead of opacity.

I highly suggest restructuring the HTML/CSS to get the effect you're looking for.

This is just an example to demonstrate the issue.

http://jsfiddle.net/K2nmL/7/

CSS

#allOptions.disabled {
  cursor: default !important;
  background-color: rgba(255,0,0,0.5);
  color: rgba(0,0,0,0.5);
}

#allOptions {
    background-color: red;
}

JavaScript

// Added a function to toggle the `disabled` class

Update

A simple solution would be to apply the opacity change to a wrapper div. I added a div that wraps the wrapper with a clearfix. This still keeps your layout the same, but it keeps all the elements inside the same stacking context.

http://jsfiddle.net/K2nmL/8/

thgaskell
  • 12,772
  • 5
  • 32
  • 38
  • You had a good idea changing just background color and color, however that does not apply to things like images, buttons (you can see one in the fiddle) and other things. I use `.disabled` class globally in my web application to render something as disabled. Would there be some other workaround, asides from setting `opacity` to foating divs? – Tomáš Zato Feb 19 '14 at 11:27
  • See my update. Buttons and inputs both support a `disabled` attribute if you really want them to be unresponsive. Here are some examples: http://jsfiddle.net/a92Fu/ – thgaskell Feb 19 '14 at 19:53
  • Here it's becoming complex... What about images? Is there really no workaround to fix my problem and keep the div transparent? When I upvoted your answer, I already thought I had one, so I didn't bother you with asking for actual workaround that works for me. However setting opacity to the floating divs too didn't help, which was the trick I planned. Now I'm really lost and out of ideas. – Tomáš Zato Feb 19 '14 at 20:32
  • Did you see my update? If you put the `#wrapper` div inside a new div _that_ div instead, you shouldn't have the issue anymore since all the elements are in the same stacking context. – thgaskell Feb 19 '14 at 20:36
  • You're really so kind and you have good ideas. But again a problem here: the floating div's *must never be opaque*. I tried your solution using 0.99 opacity (that trick of mine), but browser rounds this before applying, so it won't help. – Tomáš Zato Feb 19 '14 at 21:15
0

You cleared just one side of float - left, so the #wrapper will have 0-height issue. I've added a clearfix class:

.clear:after {
    content: "";
    display: table;
    clear: both;
}

Take a look

Also, do you need those <br> in the beginning? Better achieve same effect with padding/margin. enter image description here

Mihey Egoroff
  • 1,542
  • 14
  • 23