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?
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:
- the background and borders of the element forming the stacking context.
- the child stacking contexts with negative stack levels (most negative first).
- the in-flow, non-inline-level, non-positioned descendants.
- the non-positioned floats.
- the in-flow, inline-level, non-positioned descendants, including inline tables and inline blocks.
- the child stacking contexts with stack level 0 and the positioned descendants with stack level 0.
- 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>