I have a problem to calculate the good angle to rotate a div child of a div rotated on x axis.
To make it more understandable, I did a fast draw of what I have :
In a scene with configurable perspective (container) expressed in vh, I have a DIV element (parent DIV) that serves as a positioning rectangle for child div elements (child DIV), this parent div is tilted on the X axis by an angle that is also configurable.
My goal is to display the child divs straight facing the screen (top/bottom/right/left edges parallel to top/bottom/right/left edge of the screen) with a square shape (width=height), and therefore to calculate the negative rotation angle on the X axis, so that the child div is straight like I want, but after a lot of unsuccessful attempts and calculations (I'm not very good at maths, quite old to remember school...) I don't get a result that works on all types of settings of the perspective and the tilt angle of the parent rectangle...
I thought I simply had to do the reverse angle of the parent, ie parent angle = 50deg, child angle = -50deg, but it doesn't work like that sadly... and after some tests, I found that the value of the perspective property had an influence on the rendering of the child div too...
To illustrate what I want to do some screens of my project : This one is quite good width 57deg parent/-33deg child and also a scaleY(1.6) to the child, otherwise it's not a square, but if I change perspective or angle it goes bad...
This one is not good at all, the scene has smaller scale and my child divs arent straight while using same bad formula to calculate rotateX angle...
Any idea to help me will be much welcome !
(ps: sorry for my bad english... not my mother langage)
Edit: Did a snippet to simplify and show my problem :
#scene {
position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
width: 400px; height: 300px; perspective: 60vh; overflow: hidden; }
#recp {
position: absolute; left: 0; top: 0; width: 100%; height: 100%; background: #393;
transform: rotateX(50deg); transform-origin: bottom; backface-visibility: hidden;
transform-style: preserve-3d; perspective: 60vh; }
#recp > div {
position: absolute; width: 20%; height: 80px; background: #999;
transform: rotateX(-25deg); transform-origin: bottom;
font-size: 48px; text-align: center; line-height: 80px; }
#recp > div#elt1 { left: 0; top: 0; }
#recp > div#elt2 { left: 40%; top: 40%; }
#recp > div#elt3 { left: 80%; top: 60%; }
<div id="scene">
<div id="recp">
<div id="elt1">1</div>
<div id="elt2">2</div>
<div id="elt3">3</div>
</div>
</div>
Edit2: After some testings and readings, I understand that the only angle is not enough to solve my problem... The perspective of the parent div is also important to have a good rendering of the child, Actually I put the same value than the container perspective but it's wrong I think, this must be a value that corresponds to the positioning rectangle (parent div) itself. So the question remains as to which formula to use to calculate the correct angle on the child div and the correct perspective on the parent div...
Edit3: By dint of trial and error and without really understanding the mathematical logic of what I'm doing (mmmmhhhh...) I realize that if I keep the same perspective and apply an angle equal to half the angle of the parent div in negative, I'm almost good, give or take a few pixels... I updated the code snippet.
Maybe I need another perspective value for the parent div and be pixel-perfect, or maybe my assumption about the angle divided by 2 is not correct, I admit to being quite lost with these maths...
There is also the height of the div, I have a JS routine that goes through my child elements and assigns a height in pixels equal to the width of the image, to be sure that it is square (the width is expressed as a percentage for alignment needs on a grid), but when rendered the image is not square at all...
Edit4: Updated snippet with preserve-3d (thanks @ Temani Afif) Added W/H ratio of 4/3 on container because my project scene has this aspect ratio.
As you say, the way things are to be shown on the screen very much depends on where the observer is standing.
Luckily, no need to do complex calculations yourself, CSS can 'think' 3D.
What you have is a plain (grass) and sitting on it but vertical to it are 3 children.
So position them how you want. The one bit of calculation this snippet does is to work out where their bottoms are given where their tops would be if they were lying down flat. This is simple if you know their height - you may want to make that a variable too if the rectangles are different heights.
Then rotate the whole thing in 3D by 90 degrees - ie lay the grass down flat.
<style>
#scene {
position: absolute;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
width: 400px;
height: 300px;
overflow: hidden;
transform-style: preserve-3d;
perspective: 10vh;
}
#recp {
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
transform-style: preserve-3d;
transform: rotateX(90deg);
/* lay your grass down horizontal */
transform-origin: center bottom;
backface-visibility: hidden;
background: #393;
}
#recp>div {
position: absolute;
width: 20%;
height: 80px;
background: #999;
transform-origin: center bottom;
font-size: 48px;
text-align: center;
line-height: 80px;
bottom: calc(100% - var(--top) - 80px);
transform: rotateX(-90deg);
left: var(--left);
}
#recp>div#elt1 {
--left: 0px;
--top: 0px;
}
#recp>div#elt2 {
--left: 40%;
--top: 40%;
}
#recp>div#elt3 {
--left: 80%;
--top: 60%;
}
</style>
<div id="scene">
<div id="recp">
<div id="elt1">1</div>
<div id="elt2">2</div>
<div id="elt3">3</div>
</div>
</div>