Чтобы понять, как работает skew
, давайте сравним его с другим преобразованием, использующим угол.
Вот пример с вращением, мы устанавливаем источник преобразования равным top left
, а оттуда мы вращаемся на 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>
Для этого примера найти угол и понять, как он работает, тривиально:
Теперь давайте возьмем тот же пример и уменьшим высоту повернутого элемента до небольшого значения:
.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>
Как будто у нас повернутая линия. Теперь давайте заменим вращение на перекос:
.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>
Если мы сравним оба результата, мы заметим, что у нас как-то вращение в обоих случаях, НО другой размер, когда речь идет о перекосе:
Теперь стало понятнее, как работает перекос с углом. Преобразование является своего рода искажением, которое полагается на угол, чтобы определить это искажение. Вот лучшая иллюстрация:
Синий - это наш начальный элемент, крест - начало преобразования, а желтый - угол. Если мы сделаем поворот, мы получим красную линию, где ширина останется такой же . Если мы сделаем перекос, мы получим оранжевую линию, где ширина изменится , и с учетом иллюстрации она будет равна W / cos(angle)
Где W
- наша начальная ширина (в нашем предыдущем случае cos(45deg) = 1 / sqrt(2)
поэтому у нас будет W * sqrt(2)
).
А как насчет нашего начального квадрата, как он будет вести себя с перекосом?
.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>
Он будет вести себя точно так же, как мы описывали ранее строка за строкой . У нас также будет тот же результат, если мы применим перекос в другом направлении:
.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>
Та же логика применяется, но к вертикальным линиям и с учетом высоты. Как примечание стороны, skewX(V)
совпадает с skew(V)
ref .
Теперь, если мы применим перекос в обоих направлениях:
.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>
Как будто мы сначала применяем skewX
, чтобы исказить вертикальные линии, затем мы применяем skewY
к новой форме, чтобы исказить горизонтальные линии (или наоборот). Вот анимация, иллюстрирующая волшебный результат 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>
А как насчет происхождения? Ничто не изменится для преобразования, только ссылка изменится. Другими словами, фиксированная точка будет двигаться:
.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>
Мы также можем заметить, что если мы делаем перекос в одном направлении, будет учитываться только один параметр transform-origin
.
Таким образом, для skewX
, transform-origin: X Y
будет таким же, как и значение X
. Это как-то объясняет преобразование строка за строкой , так как когда мы в сети, у нас есть одно измерение.
.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>
Подробнее
Теперь давайте рассмотрим матричный расчет, чтобы понять, как он используется и как tan(angle)
также используется.
Если мы ссылаемся на документацию , то имеем:
Эта матрица используется для определения координат преобразованного элемента на основе координаты исходного элемента точка за точкой. Учитывая это определение, мы получим эти уравнения
Xf = Xi + Yi * tan(ax)
Yf = Xi * tan(ay) + Yi
Если мы рассмотрим только skewY
, то ясно, что ax
будет 0
, поэтому tan(0)
будет 0
и X
не изменится, что имеет место в нашем первом примере, где мы имели только искажение по оси Y (та же логика, если мы применяем только skewY).
Теперь, почему у нас Yf = Xi * tan(ay) + Yi
?
Давайте снова возьмем предыдущую иллюстрацию:
Зеленая точка - это начальная точка, определенная Xi,Yi
, а красная точка - это преобразованная точка, определенная Xf,Yf
. Тривиально, что Xf=Xi
и расстояние между двумя точками будет Yf-Yi
.
Рассматривая иллюстрацию, мы можем четко сказать, что tan(ay) = (Yf-Yi)/Xi = (Yf-Yi)/Xf
, таким образом, у нас будет:
Xf = Xi
Yf = Xi * tan(ay) + Yi
Мы применяем ту же логику, если имеем перекос в другом направлении.