Can anyone explain this behavior?
I have three nested elements: a container div
, a subcontainer div
and a "shape/image" div
. The markup is like below:
<html>
<div class="container">
<div class="subcontainer">
<div class="shape"></div>
</div>
</div>
</html>
When I apply transform: translateZ()
to the shape, obviously it will only work if one of the parents has some perspective
applied. It doesn't need to be necessarily the direct parent, it can be the parent's parent div
(the container). When the container has the perspective
, the shape moves in the z direction fine. But, when the subcontainer (the parent) has something in the transform
, other than unset
, the translateZ()
from the shape is fully ignored. Of course, applying perspective
to the direct parent makes the translateZ()
in the shape work, but I wanted to understand what in the parent transform
blocks the perspective
to be seen by the shape:
Below works:
.container{
perspective: 1000px;
}
.subcontainer{
transform: unset; // <- or if this is not present at all
}
.shape{
transform: translateZ(300px);
}
Below doesn't work:
.container{
perspective: 1000px;
}
.subcontainer{
transform: scale(1.001);
}
.shape{
transform: translateZ(300px); // <- this is fully ignored
}
Here is this example in codepen.
EDIT:
In many docs I read that perspective
must be a property set in the parent element. But MDN seems to show that it can in fact be set in the intended element itself, inside the transform
rule. So, is perspective: 500px
in the parent equivalent to transform: perspective(500px)
in the child?
From the specification:
By default, transformed elements do not create a 3D rendering context and create a flattened representation of their content. However, since it is useful to construct hierarchies of transformed objects that share a common 3-dimensional space, this flattening behavior may be overridden by specifying a value of
preserve-3d
for thetransform-style
property. This allows descendants of the transformed element to share the same 3D rendering context.
So simply add transform-style:preserve-3d
to the subcontainer element and the perspective of the grand-parent will be respected:
.container{
background: #f4f7be;
height: 100vh;
width: 100vw;
display: flex;
justify-content: center;
align-items: center;
perspective: 1000px;
}
.subcontainer{
background: #baf7f6;
width: 70%;
height: 70%;
display: flex;
justify-content: center;
align-items: center;
transform: scale(1.001);
transform-style:preserve-3d;
}
.shape{
background: #555;
width: 40%;
height: 50%;
clip-path: polygon(50% 0%, 0% 100%, 100% 100%);
transform: translateZ(300px);
}
<html>
<div class="container">
<div class="subcontainer">
<div class="shape"></div>
</div>
</div>
</html>
So, is perspective: 500px in the parent equivalent to transform: perspective(500px) in the child?
Not exactly equivalent because you need to consider other factors like the parent dimension, transform-origin, perspective-origin, etc
A trivial example:
.box {
padding: 20px;
border: 1px solid;
}
.box>div {
width: 100px;
height: 100px;
background: red;
}
<div class="box" style="perspective:100px;">
<div style="transform:translateZ(10px);"></div>
</div>
<div class="box">
<div style="transform:perspective(100px) translateZ(10px);"></div>
</div>
The difference is due to the origin. In the first case, the perspective will use the center of the parent as origin (because perspective-origin
is center by default). In the second case, the center of the element will be used as origin (because transform-origin
is center by default)
Related questions for more detail and examples:
perspective and translateZ moves diagonally
Why perspective isn't giving the same result when some styles are updated?
CSS 3d transform doesn't work if perspective is set in the end of property
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With