16

I'm having a strangs CSS problem.

Below is a very simple code sample, demonstrating the problem.

<html>
  <head>
     <style>
      .hover {
        float: right;
      }
      .hover:hover {
        background-color: blue;
      }
      .blocker {
        opacity: 0.5;
      }
    </style>
  </head>
  <body>
    <div class="hover">hover</div>
    <div class="blocker">blocker</div>
  </body>
</html>

I have a div A, floating over another div B, which has an opacity of 0.5. And I want to add a CSS hover rule to the floating div. But for some reason I can't.

Whether I float right or left, doesn't matter.

But when I change the opacity to 1, the hover rule works all of a sudden.

Can anybody explain this behaviour?

I can "fix" the problem by wrapping the content of the blocker div in a span, but it feels like I shouldn't have to.

Here's a jsFiddle, demonstrating the problem: http://jsfiddle.net/ed82z/1/

Jipo
  • 330
  • 2
  • 6
  • 5
    None of the answer below seems to bring any explanation regarding why setting the opacity to 1 works but not 0.5. – Denys Séguret Jun 02 '14 at 13:36
  • This will give you a clue: http://jsfiddle.net/abhitalks/ed82z/4/ – Abhitalks Jun 02 '14 at 13:38
  • 2
    Stacking Context: [(see this)](https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/The_stacking_context) *"A stacking context is formed, anywhere in the document, by any element which is either...elements with an opacity value less than 1"* – Abhitalks Jun 02 '14 at 13:47
  • 1
    This link is interesting but far from being precise enough to explain what happens here, IMO. – Denys Séguret Jun 02 '14 at 13:57
  • @dystroy: yes. that's why just a comment and not an attempted answer. – Abhitalks Jun 02 '14 at 14:00

3 Answers3

20

Simply put - it is "above" it if the opacity has a less than 1 value.

The key term here is a Stacking Context.

By setting opacity to a value less than one, it is layered differently according to the specification since it receives a new stacking context and is positioned beneath the element.

It is specified here float and in opacity:

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. In future levels of CSS, other properties may introduce stacking contexts, for example 'opacity' [CSS3COLOR].

From opacity:

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

How to fix it:

You can set pointer-events to none , see this fiddle.

Community
  • 1
  • 1
Benjamin Gruenbaum
  • 270,886
  • 87
  • 504
  • 504
  • "it is above" - unless you set the z-index to something negative? – John Dvorak Jun 02 '14 at 13:50
  • Hmmm The contents of floats are stacked as if floats generated new stacking contexts, except that any positioned elements and elements that actually create new stacking contexts take part in the float's parent stacking context. A float can overlap other boxes in the normal flow (e.g., when a normal flow box next to a float has negative margins). When this happens, floats are rendered in front of non-positioned in-flow blocks, but behind in-flow inlines. – Benjamin Gruenbaum Jun 02 '14 at 13:52
  • @JanDvorak yes, you can use z-index to "solve" this : http://jsfiddle.net/webtiki/ed82z/6/ – web-tiki Jun 02 '14 at 13:54
  • @j08691 I've updated the citation to the correct one. – Benjamin Gruenbaum Jun 02 '14 at 13:54
  • https://developer.mozilla.org/en-US/docs/Web/Guide/CSS/Understanding_z_index/Stacking_and_float <- *If the opacity of a non-positioned block is reduced, then something strange happens: the background and border of that block pops up above the floating blocks, but still under positioned blocks.* – adeneo Jun 02 '14 at 13:55
  • @adeneo yes, that's pretty much what the answer says – Benjamin Gruenbaum Jun 02 '14 at 13:57
  • 1
    What disturbs me is that you can't fix it by setting explicit z-indexes. – Denys Séguret Jun 02 '14 at 13:57
  • @dystroy I have added a solution to that. – Benjamin Gruenbaum Jun 02 '14 at 13:59
  • @BenjaminGruenbaum - Well, yes, I'm just noting that MDN said it ten years ago ! – adeneo Jun 02 '14 at 14:01
  • @BenjaminGruenbaum I didn't mean I was disturbed because it's hard to fix (there are so many east ways), I'm disturbed because the quote you give seems to imply that setting explicit z-indexes should fix it. Which makes me wonder if you really explained the problem here. – Denys Séguret Jun 02 '14 at 14:02
  • 1
    @dystroy I don't think the quote implies setting explicit z-indexes should fix it because z-index is not applicable to non-positioned elements. – James Montagne Jun 02 '14 at 14:28
  • @JamesMontagne You're right. That settles it to me, this looks like the right answer. – Denys Séguret Jun 02 '14 at 14:35
4

Adding overflow: hidden worked for me:

.blocker {
    opacity: 0.5;
    overflow:hidden;
}

Or:

.blocker { 
        opacity: 0.5;
        position:relative; 
        z-index:-1;
}

(thank you @Eyal Barta for this option)

http://jsfiddle.net/ed82z/7/

This is because .blocker overlays your other div, easily shown with firebug or other dev tools.

When you add opacity you add a 'stacking context'.

This occurs because these DIVs have special properties which cause them to form a stacking context.

In this case: elements with an opacity value less than 1. Which is giving your div a z-index, and it is causing the div to be rendered in a different order.

The Stacking Context

Aravona
  • 528
  • 6
  • 21
0

In .blocker class is overlapping the .hover class because of float:right;

.blocker {
    opacity: 0.5; 
    width:100px
}

you can fix this set float:left in blocker class or else set width:100px to fixed width for div it won't overlap.

Anand Thangappan
  • 3,068
  • 2
  • 28
  • 31