Why does "position: relative" interfere with "transform: scale"?
Asked Answered
O

1

6

Given the following markup and style

div {
  width: 300px;
  height: 50px;
  border: 1px solid black;
  display: inline-block;
  transition: all .1s ease-in-out;
  background-color: white;
  padding: 0px 5px;
}
div:hover {
  transform: scale(1.2);
}
label {
  /*position: relative;*/
}
<div>
  <label>some random text</label>
</div>
<div>
  <label>some random text</label>
</div>

when hovering over the first div some letter from the second div are being "hidden" under the scaled element. When, however, position: relative is set on the label element, the text gets rendered over the scaled element:

div {
  width: 300px;
  height: 50px;
  border: 1px solid black;
  display: inline-block;
  transition: all .1s ease-in-out;
  background-color: white;
  padding: 0px 5px;
}
div:hover {
  transform: scale(1.2);
}
label {
  position: relative;
}
<div>
  <label>some random text</label>
</div>
<div>
  <label>some random text</label>
</div>

I'm trying to understand the reasoning behind this. Since this seams consistent across browsers, I'm thinking that it is defined in the specs. If so, what's the rationale? And how do I "turn it off", if can't touch the relative positioning?

Orlando answered 17/2, 2016 at 15:31 Comment(1)
Eh... it's not really interfering. What you're seeing is a z-index stacking issue. Your labels have a position other than static which implicitly changes the rendering to be "on top" of other elements including the containing divsGrillo
R
5

Applying a transform to an element causes it to establish a new stacking context.

Positioning an element (i.e. setting its position to something other than static) doesn't necessarily cause it to establish a stacking context, in particular a relatively positioned element with z-index: auto (the default) does not establish a stacking context.

That being said, both types of elements are grouped together in the painting order defined in section 9.9 of CSS2.1:

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

When you hover the first div, it becomes a child stacking context with stack level 0, but this child stacking context participates in the same parent stacking context as the label in the second div as the second div itself doesn't establish a stacking context.

As all of your elements have the same stack level of 0 (based on the default z-index: auto), the spec says:

Boxes with the same stack level in a stacking context are stacked back-to-front according to document tree order.

Since your first div occurs before the second div and its label, the label of the second div is painted over the first div despite the transform.

You can fix this by specifying z-index: 1 on div:hover:

div {
  width: 300px;
  height: 50px;
  border: 1px solid black;
  display: inline-block;
  transition: all .1s ease-in-out;
  background-color: white;
  padding: 0px 5px;
}
div:hover {
  transform: scale(1.2);
  z-index: 1;
}
label {
  position: relative;
}
<div>
  <label>some random text</label>
</div>
<div>
  <label>some random text</label>
</div>
Rebeccarebecka answered 17/2, 2016 at 15:48 Comment(6)
Whoohoo! You go, BoltClock! Nice answer.Grillo
@Joseph Marikle: Aw you make me blush - considering you even deleted your +2 answer!Rebeccarebecka
It wasn't nearly as well researched as yours. I'll probably bookmark this for when I need to find the stacking level on W3C. I swear that site makes it entirely too dificult to find anything.Grillo
@Joseph Marikle: Funnily enough, I actually have a handful of answers that all point to the same list. And none of the questions I answered are duplicates of one another.Rebeccarebecka
Thank you for your excellent answer. I've learned some interesting things from it. I'm just going to say that you probably didn't test it in Chrome/Opera. I've actually tried setting the z-index before posting the question, but without luck. If I would have also tested it in Firefox or even Internet Explorer, I could have seen that the results are different.Orlando
@Rebeccarebecka I have a similar html ... but the problem is that 'position: relative' is causing text blurry..if I remove the 'position relative' the text becomes clear.. the text blurry disappears..Erwinery

© 2022 - 2024 — McMap. All rights reserved.