How can I create a quadrilateral with css, when I know which degree each corner has.
I already tried to recreate a quadrilateral I have with transform and skew.
However, this does not work really well.
This is what I try to archive.
The exact requirements are:
A div with this as background in one color. On the image are just construction lines. It should be a solid quadrilateral with these angles.
This was my first idea:
transform: rotate(-45deg) skew(27.5deg, 62.5deg)
transform-origin: top center;
I would consider multiple background to achieve this where I simply need to find the width/height of the element. Based on your illustration we have this:
From this we can have the following formula:
tan(alpha) = W/H
and
tan(beta/2) = H/W
We only need to use one of them and you will notice that there isn't one solution which is logical as you simply need to keep a ratio between H
and W
and the width of our element will simply be 2*W
and its height 2*H
.
Since H/W
is also the same as 2*H/2*W
we can simply consider that width = tan(alpha)*height
.box {
height:var(--h);
width:calc(1.92098213 * var(--h)); /* tan(62.5)xH */
background:
linear-gradient(to bottom right,transparent 49%,red 50%) top left,
linear-gradient(to top right,transparent 49%,red 50%) bottom left,
linear-gradient(to bottom left ,transparent 49%,red 50%) top right,
linear-gradient(to top left ,transparent 49%,red 50%) bottom right;
background-size:50% 50%;
background-repeat:no-repeat;
}
<div class="box" style="--h:50px;"></div>
<div class="box" style="--h:100px;"></div>
<div class="box" style="--h:200px;"></div>
You can adjust the gradient if you want only borders:
.box {
height:var(--h);
width:calc(1.92098213 * var(--h)); /* tan(62.5)xH */
background:
linear-gradient(to bottom right,transparent 49%,red 50%,transparent calc(50% + 2px)) top left,
linear-gradient(to top right,transparent 49%,red 50%,transparent calc(50% + 2px)) bottom left,
linear-gradient(to bottom left ,transparent 49%,red 50%,transparent calc(50% + 2px)) top right,
linear-gradient(to top left ,transparent 49%,red 50%,transparent calc(50% + 2px)) bottom right;
background-size:50% 50%;
background-repeat:no-repeat;
}
<div class="box" style="--h:50px;"></div>
<div class="box" style="--h:100px;"></div>
<div class="box" style="--h:200px;"></div>
Using transform the idea is to rely on rotateX()
in order to visually decrease the height to keep the formula defined previously. So we start by having Width=height
(a square) then we rotate like below:
This is a view from the side. The green is our rotated element and the red the initial one. It's clear that we will see the height H1
after performing the rotation and we have this formula:
cos(angle) = H1/H
And we aleardy have tan(alpha)=W/H1
so we will have
cos(angle) = W/(H*tan(alpha))
and H=W
since we defined a square initially so we will have cos(angle) = 1/tan(alpha) --> angle = cos-1(1/tan(alpha))
.box {
width:150px;
height:150px;
background:red;
margin:50px;
transform:rotateX(58.63017731deg) rotate(45deg); /* cos-1(0.52056)*/
}
<div class="box">
</div>
We can also apply the same logic using rotateY()
to update the width in the situation where you will have beta bigger than 90deg
and alpha smaller than 45deg
. In this case we will have W < H
and the rotateX()
won't help us.
The math can easily confirm this. when alpha
is smaller than 45deg
tan(alpha)
will be smaller than 1
thus 1/tan(alpha)
will bigger than 1
and cos
is only defined between [-1 1]
so there is no angle we can use with rotateX()
Here is an animation to illustrate:
.box {
width:100px;
height:100px;
display:inline-block;
background:red;
margin:50px;
animation:change 5s linear infinite alternate;
}
.alt {
animation:change-alt 5s linear infinite alternate;
}
@keyframes change {
from{transform:rotateX(0) rotate(45deg)}
to{ transform:rotateX(90deg) rotate(45deg)}
}
@keyframes change-alt {
from{transform:rotateY(0) rotate(45deg)}
to{ transform:rotateY(90deg) rotate(45deg)}
}
<div class="box">
</div>
<div class="box alt">
</div>