To understand how skew
works let's compare it with another transformation that uses angle.
Here is an example with rotation, we make the transform origin to be top left
and from there we rotate by 45deg
:
.box {
margin:50px;
width:200px;
height:200px;
background:blue;
}
.box > div {
height:100%;
width:100%;
background:rgba(255,0,0,0.5);
transform-origin:top left;
transform:rotate(45deg);
}
<div class="box">
<div></div>
</div>
For this example, it's somehow trivial to find the angle and how it works:
Now let's take the same example and reduce the height of the rotated element to a small value:
.box {
margin:50px;
width:200px;
height:200px;
background:blue;
}
.box > div {
height:3px;
width:100%;
background:red;
transform-origin:top left;
transform:rotate(45deg);
}
<div class="box">
<div></div>
</div>
It's like we have a rotated line. Now let's replace rotate with skew:
.box {
margin:50px;
width:200px;
height:200px;
background:blue;
}
.box > div {
height:3px;
width:100%;
background:red;
transform-origin:top left;
transform:skewY(45deg);
}
<div class="box">
<div></div>
</div>
If we compare both result we will notice that we have somehow a rotation in both cases BUT a different size when it comes to skew transformation:
It's more clear now how skew works with angle. The transform is a kind of distortion that rely on an angle to define this distortion. Here is a better illustration:
The blue is our initial element, the cross is the transform origin and the yellow is the angle. If we do a rotation we will obtain the red line where the width remain the same. If we do a skew we will obtain the orange line where the width will change and considering the illustration it will be equal to W / cos(angle)
Where W
is our initial width (in our previous case cos(45deg) = 1 / sqrt(2)
so we will have W * sqrt(2)
).
Now what about our intial square, how it will behave with skew?
.box {
margin:50px;
width:200px;
height:200px;
background:blue;
}
.box > div {
height:100%;
width:100%;
background:red;
transform-origin:top left;
transform:skewY(45deg);
}
<div class="box">
<div></div>
</div>
It will behave exactly like we described previously line by line. We will also have the same result if we apply skew in the other direction:
.box {
margin:50px;
width:200px;
height:200px;
background:blue;
}
.box > div {
height:100%;
width:100%;
background:red;
transform-origin:top left;
transform:skewX(45deg);
}
<div class="box">
<div></div>
</div>
The same logic is applied but to vertical lines and considering the height. As a side note, skewX(V)
is the same as skew(V)
ref.
Now if we apply skew in both direction:
.box {
margin:50px;
width:200px;
height:200px;
background:blue;
}
.box > div {
height:100%;
width:100%;
background:red;
transform-origin:top left;
transform:skew(45deg,10deg);
}
<div class="box">
<div></div>
</div>
It's like we first apply skewX
to distort the vertical lines then we apply skewY
to the new shape to distort the horizontal lines (or the opposite). Here is an animation to illustrate the magic result of skew(45deg,45deg)
:
.box {
margin:50px;
width:200px;
height:200px;
background:blue;
}
.box > div {
height:100%;
width:100%;
background:red;
transform-origin:top left;
transform:skew(45deg,10deg);
animation:change 5s infinite alternate linear;
}
@keyframes change {
from {
transform:skew(0deg,0deg);
}
50% {
transform:skew(45deg,0deg);
}
to {
transform:skew(45deg,45deg);
}
}
<div class="box">
<div></div>
</div>
And what about origin? Nothing will change for the transformation, only the reference will change. In other words, the fixed point will move:
.box {
margin:50px;
width:200px;
height:200px;
background:blue;
}
.box > div {
height:100%;
width:100%;
background:red;
transform-origin:center;
transform:skew(45deg,10deg);
animation:change 5s infinite alternate linear;
}
@keyframes change {
from {
transform:skew(0deg,0deg);
}
50% {
transform:skew(45deg,0deg);
}
to {
transform:skew(45deg,45deg);
}
}
<div class="box">
<div></div>
</div>
We may also notice that if we do skew in one direction only one parameter of transform-origin
will be considered.
So for skewX
, transform-origin: X Y
will be the same whataver the value of X
is. This somehow explain the line by line transformation as when we have on line we have one dimension.
.box {
margin:50px;
width:200px;
height:200px;
background:blue;
}
.box > div {
height:100%;
width:100%;
background:red;
transform:skewX(45deg);
animation:change 5s infinite alternate linear;
}
@keyframes change {
from {
transform-origin:0 0;
}
50% {
transform-origin:100% 0;/*nothing will happen between 0 and 50%*/
}
to {
transform-origin:100% 100%;
}
}
<div class="box">
<div></div>
</div>
More in depth
Now let's consider the matrix calculation to understand how it's used and how tan(angle)
is also used.
If we refer to the documentation we have:
This matrix is used to define the coordinates of the transformed element based on the coordinate of the initial element point by point. Considering this definition we will have these equations
Xf = Xi + Yi * tan(ax)
Yf = Xi * tan(ay) + Yi
If we consider skewY
only it's clear that ax
will be 0
thus tan(0)
will be 0
and X
won't change which is the case with our first example where we only had distortion in the Y axis (same logic if we apply only skewY).
Now, why we have Yf = Xi * tan(ay) + Yi
?
Let's re-take the previous illustration:
The green point is the initial point defined by Xi,Yi
and the red point is the tranformed one defined by Xf,Yf
. It's trivial that Xf=Xi
and the distance between the two points will be Yf-Yi
.
Considering the illustration we can clearly say that tan(ay) = (Yf-Yi)/Xi = (Yf-Yi)/Xf
thus we will have:
Xf = Xi
Yf = Xi * tan(ay) + Yi
We apply the same logic if we have skew in the other direction.
transform
is retuned as amatrix()
func. So it is actuallyrotate(∂)
which gets transformed tocos(∂), sin(∂), -sin(∂), cos(∂), x, y)
– Layla