Чтобы проиллюстрировать, как это работает, давайте рассмотрим анимацию, показывающую, как эффект масштабирования изменяет вращение.
.red {
width:80px;
height:20px;
background:red;
margin:80px;
transform-origin:left center;
animation: rotate 2s linear infinite;
}
@keyframes rotate {
from{transform:rotate(0)}
to{transform:rotate(360deg)}
}
<div class="container">
<div class="red">
</div>
</div>
Как вы можете видеть выше, вращение создает идеальную форму круга.
Теперь давайте масштабируем контейнер и видим разницу:
.red {
width:80px;
height:20px;
background:red;
margin:80px;
transform-origin:left center;
animation: rotate 5s linear infinite;
}
@keyframes rotate {
from{transform:rotate(0)}
to{transform:rotate(360deg)}
}
.container {
display:inline-block;
transform:scale(3,1);
transform-origin:left center;
}
<div class="container">
<div class="red">
</div>
</div>
Обратите внимание, что у нас больше нет круга, но теперь это эллипс.Это как если бы мы взяли круг и зачеркнули его, создавая эффект перекоса внутри нашего прямоугольника.
Если мы делаем противоположный эффект, и мы начинаем с эффекта масштаба, а затем мы применяем вращение, которое мыне будет никакого перекоса.
.red {
width:80px;
height:20px;
background:red;
margin:80px;
animation: rotate 2s linear infinite;
}
@keyframes rotate {
from{transform:scale(1,1)}
to{transform:scale(3,1)}
}
.container {
display:inline-block;
transform:rotate(30deg);
transform-origin:left center;
}
<div class="container">
<div class="red">
</div>
</div>
Чтобы объяснить это по-разному: применение поворота сохранит одинаковое соотношение между осями X и Y, поэтому вы не увидите никакого плохого эффекта при последующем масштабированиино масштабирование только одной оси нарушит соотношение, поэтому наша фигура выглядит плохо, когда мы пытаемся применить вращение.
Вы можете проверить эту ссылку, если хотите получить более подробную информацию о том, как преобразование связано и какМатрица рассчитана: https://www.w3.org/TR/css-transforms-1/#transform-rendering. Речь идет об элементе HTML, но, как сказано в спецификации SVG, это то же самое.
Вот соответствующие части:
Преобразования являются кумулятивными.То есть элементы устанавливают свою локальную систему координат в системе координат своего родителя.
С точки зрения пользователя, элемент эффективно накапливает все свойства преобразованияего предков, а также любое локальное преобразование, примененное к нему
Давайте сделаем некоторую математику, чтобы увидеть разницу между обоими преобразованиями.Давайте рассмотрим матричное умножение, и, поскольку мы имеем дело с двумерным линейным преобразованием, мы сделаем это на ℝ² для простоты 1 .
Для scale(2, 1) rotate(10deg)
у нас будет
|2 0| |cos(10deg) -sin(10deg)| |2*cos(10deg) -2*sin(10deg) |
|0 1| x |sin(10deg) cos(10deg) | = |1*sin(10deg) 1*cos(10deg) |
Теперь, если мы применим эту матрицу к (Xi,Yi)
, мы получим (Xf,Yf)
, как показано ниже:
Xf = 2* (Xi*cos(10deg) - Yi*sin(10deg))
Yf = Xi*sin(10deg) + Yi*cos(10deg)
Обратите внимание, что Xf
имеет дополнительный множитель, который равенвиновник создания эффекта перекоса.Как будто мы изменили поведение или Xf
и сохранили Yf
Теперь давайте рассмотрим rotate(10deg) scale(2, 1)
:
|cos(10deg) -sin(10deg)| |2 0| |2*cos(10deg) -1*sin(10deg) |
|sin(10deg) cos(10deg) | x |0 1| = |2*sin(10deg) 1*cos(10deg) |
И тогда у нас будет
Xf = 2*Xi*cos(10deg) - Yi*sin(10deg)
Yf = 2*Xi*sin(10deg) + Yi*cos(10deg)
Мы можем рассматривать 2*Xi
как Xt
, и мы можем сказать, что мы повернули (Xt,Yi
) элемент, и этот элемент был первоначально масштабирован с учетом оси X.
1 CSS использует также аффинное преобразование (например, translate), поэтому использование ℝ² (декартовы координаты) недостаточно для выполнения нашего расчета, поэтому мы должны рассмотреть ℝℙ² (однородные координаты).Наш предыдущий расчет будет:
|2 0 0| |cos(10deg) -sin(10deg) 0| |2*cos(10deg) -2*sin(10deg) 0|
|0 1 0| x |sin(10deg) cos(10deg) 0| = |1*sin(10deg) 1*cos(10deg) 0|
|0 0 1| |0 0 1| |0 0 1|
В этом случае ничего не изменится, потому что аффинная часть равна null , но если у нас есть перевод, объединенный с другим преобразованием (например: scale(2, 1) translate(10px,20px)
)у нас будет следующее:
|2 0 0| |1 0 10px| |2 0 20px|
|0 1 0| x |0 1 20px| = |0 1 20px|
|0 0 1| |0 0 1 | |0 0 1 |
и
Xf = 2*Xi + 20px;
Yf = Yi + 20px;
1 = 1 (to complete the multiplication)