3

I have a block with .cube class - which implement a red cube.

.cube {
    position: absolute;
    top: 50px;
    left: 50px;
    width: 20px;
    height: 20px;
    background: red;
    transition: .3s opacity;
}

And pseudo-selector :before with a "border" around it (actually it's just more larger cube around .cube class).

.cube::before {
    position: absolute;
    top: -10px; left: -10px;
    right: -10px; bottom: -10px;
    content: '';
    background: black;
    z-index: -1;
}

On :hover I change my opacity in .cube class.

.cube:hover {
    opacity: .5;
}

The question is: why .cube class on hover is disappears, in turn, it is not "under" :before. Where it?

Here is JSFiddle. Thanks!

.cube {
 position: absolute;
 top: 50px;
 left: 50px;
 width: 20px;
 height: 20px;
 background: red;
 transition: .3s opacity;
}

.cube::before {
 position: absolute;
 top: -10px; left: -10px;
 right: -10px; bottom: -10px;
 content: '';
 background: black;
 z-index: -1;
}

.cube:hover {
 opacity: .5;
}
<div class="cube"></div>
AleshaOleg
  • 2,171
  • 1
  • 15
  • 29
  • 2
    Because opacity changes the stacking order as I recall. – Paulie_D Jul 19 '16 at 11:34
  • @Paulie_D yeah, but opacity is .5 - where is red cube? To your mind, it should be "under" `:before` block, isn't it? – AleshaOleg Jul 19 '16 at 11:36
  • 1
    That's what I'm saying the stacking order changes and so now the red cube is under the `::before`. – Paulie_D Jul 19 '16 at 11:42
  • @Paulie_D but opacity is .5, we should see red cube under black – AleshaOleg Jul 19 '16 at 11:44
  • Hmmm...that is weird. When I inspect it the computed opacity of the pseduo-element is still 1... – Paulie_D Jul 19 '16 at 11:52
  • That is odd - what is your desired behaviour on `hover`? How do you want it to look? – Mike Harrison Jul 19 '16 at 12:18
  • @MikeHarrison I just want to know - where is my red block?:) – AleshaOleg Jul 19 '16 at 12:19
  • 1
    i think as @Paulie_D said it should be happening like that. one more example to check out. https://jsfiddle.net/ek8q0mrs/7/ – tejpal Jul 19 '16 at 12:26
  • @tejpal it happened, but if I have black block with opacity: 0.5, I should see the red one. Where is it? – AleshaOleg Jul 19 '16 at 12:28
  • Actually, the weird thing is that your cube is visible in the first place, and that, because the `:before` is not before, but **inside** the `.cube`. Using a `transform: translate3d(0,0,0);` to the `.cube` will force the renderer to come to it's senses. – xpy Jul 19 '16 at 12:35
  • @xpy I don't need to force it - I want to know where is red block, after hover on it – AleshaOleg Jul 19 '16 at 12:40
  • 2
    @AleshaOleg, I suppose you don't, but what I believe, is that the `:hover` behavior is the correct behavior, and the initial state is a bug, so you shouldn't rely on that. And that probably happens because the `.cube` doesn't have a `z-index` defined and thus the renderer gets confused. – xpy Jul 19 '16 at 12:47
  • @xpy yeah, i think too - it's correct behavior. – AleshaOleg Jul 19 '16 at 13:46

1 Answers1

2

Paulie_D was right! The stacking context is being affected. Check this out here for more information:

https://www.w3.org/TR/css3-color/#transparency

I decided to modify your example to show what's going on a bit more easily. I must say, you don't see browser stacking context coming into play this way every day! (Sorry)

Here's what I've done:

  • Extended the duration of the original transition
  • Added a transition of a different time to differentiate each direction of the interim change.
  • Changed the color from black to cyan to help with visual color changes (A brighter color will help one see the difference between 'above' and 'below' in stack
  • Added a reduced opacity style to the (presently) cyan colored :before element.

Here's the fiddle:
https://jsfiddle.net/c5d5thhk/

Instructions: Mouse over the box. Please Note:

  • the change in color relative to the timing of the relevant transition.
  • that the appearance in color (affected by opacity) never truly finishes changing back to its initial state (until an end-'flick' at the very end of the transition) when coded like this. This is because the inherent change in stacking context is never allowed to return back to the initial state smoothly as the transition commands. This is why I've changed the coloring to cyan and added the opacity rules that I have.
  • Don't forget: ::before is inherently before the rest of the element in source order. It may help to see this fiddle with ::before changed to ::after to help demonstrate the other side of the fence. https://jsfiddle.net/c5d5thhk/1/

And yes, there is some buggy behavior on several browsers for this demo; sometimes the transition never allows the stacking context to return to its initial order, even when the opacity has finished its course in the transition's entire duration of 3s (3 seconds) - if this gets in the way of your testing, play around with the mouse a bit; the agitation should cause it to resolve within a few moments if it doesn't on its own.

Edit:

Just saw that the MDN has a much clearer breakdown than the W3C (surprise, surprise) on how the stacking context goes. Check it out here:
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Positioning/Understanding_z_index/The_stacking_context

Also, check this out for influencing stacks:
https://developer.mozilla.org/en-US/docs/Web/CSS/isolation

Edit 2: (added comment)
Here's a bit more information. As for your repeated question, your red box's box model is behind the black box. However, because of the rendering process taken to address transparency, it isn't shown in your example when the opacity style is engaged. In other words: even though the black box has a reduced opacity where one expects to have any content behind it revealed, the red box will still not be shown because of the process taken for the alpha channel. If you'd like to learn more about this, try running this with an SVG.

MassDebates
  • 917
  • 6
  • 10
  • Hey! Thanks for your answer. But, I think, it's not a bug. As mentioned in answer of this [http://stackoverflow.com/questions/3032856/z-index-of-before-or-after-to-be-below-the-element-is-that-possible](question) we create a new stacking context for our element (for `.cube` in our case) with a help of `posiotion: absolute; z-index: -1px`. That's why opacity will be applied to `:before` and that's why we can't see red block. Isn't it? So, I should repeat my question. Where my red block in this case, without any changes? – AleshaOleg Jul 19 '16 at 14:56
  • I didn't say the original phenomenon was a bug. `User @xpy` is incorrect in his comment, saying that the initial state -is- a bug. the bug I was mentioning is the fact that the returning `transition` is not smoothly processed. I invite you to check my demos. Your red box is where it should be the entire time. The stack is being changed, **as per spec**, by the styling that change opacity. (Edit: Added @ and ` ticks for User notation) – MassDebates Jul 19 '16 at 15:00
  • 1
    Here's a bit more information. As for your repeated question, your red box's `box model` is *behind* the black box. However, because of the rendering process taken to address transparency, it isn't shown in your example when the `opacity` style is engaged. In other words: **even though the black box has a reduced opacity where one expects to have any content *behind* it revealed, the red box will still not be shown because of the process taken for the alpha channel**. If you'd like to learn more about this, try running this with an SVG. (Edit: had "1" on outside of box model, replaced with ` ) – MassDebates Jul 19 '16 at 15:09
  • Yeah, that's right. Could you add this to answer? I will mark it like correct answer. – AleshaOleg Jul 19 '16 at 16:44
  • Sure thing-I think it'll be good to have these comments as part of the answer for other readers stumbling upon this phenomenon. If you are looking for a way around this with a similar situational context, I would suggest a crude solution along the lines of modifying the dimensions of the elements to reverse their larger/smaller (to smaller/larger) relationship (to only just a bit! like `1px`) and running a `box-shadow` to 'fake' it. I believe that if the element isn't entirely covered, the limitation is no longer applicable, and the `box-shadow` would help preserve the initial box's appearance – MassDebates Jul 19 '16 at 17:40