Матрица трансформаций: matrix() и matrix3d()

matrix() и matrix3d() - это "сырой" вид, к которому браузер сводит абсолютно любой transform: translate, rotate, scale и skew из прошлых уроков. matrix() - шесть чисел для двумерных трансформаций, matrix3d() - шестнадцать чисел для трёхмерных (rotateX, rotateY, translateZ). Именно это ты увидишь в DevTools, даже если в коде написаны обычные читаемые функции.

Попробуй прямо сейчас: в состоянии покоя у блока написано transform: matrix(1, 0, 0, 1, 0, 0) - это "пустая", единичная матрица, которая ничего не меняет, точно как transform: none. При наведении включается transform: matrix(0.866025, 0.5, -0.5, 0.866025, 40, 20) - ОДНА строка, которая одновременно сдвигает блок на 40px вправо и 20px вниз и поворачивает его на 30 градусов. Это ровно то же самое, что transform: translate(40px, 20px) rotate(30deg) - просто уже посчитанное браузером наперёд.

matrix(): шесть чисел вместо translate, rotate, scale и skew

Любая комбинация translate/rotate/scale/skew в итоге превращается в шесть чисел: matrix(a, b, c, d, tx, ty). Первые четыре числа отвечают за поворот и масштаб: a и d - это масштаб (или косинус угла поворота), b и c - наклон (или синус угла поворота). Последние два, tx и ty, - это чистый сдвиг по горизонтали и вертикали. Например, rotate(45deg) даёт matrix(0.707, 0.707, -0.707, 0.707, 0, 0), а translate(40px, 25px) - matrix(1, 0, 0, 1, 40, 25). Собственная проверка показала любопытную деталь: точка трансформации из прошлого урока в эту матрицу вообще не попадает - transform-origin применяется браузером отдельно при отрисовке, поэтому одна и та же матрица получается независимо от того, где стоит точка. А вот что действительно видно в матрице - это разница из урока про порядок функций: translate(80px,0) rotate(45deg) даёт tx=80, а rotate(45deg) translate(80px,0) - tx=56.57 - та же самая асимметрия, только теперь в виде голых чисел.

.card { transform: translate(40px, 20px) rotate(30deg); } - понятно, что делает код, и легко поменять только сдвиг или только угол.

Неправильный ход - пытаться "увеличить масштаб в 2 раза", подправив вручную только a и d в готовой матрице с поворотом:

.card { /* было: matrix(1.732, 1, -1, 1.732, 40, 20) - поворот 30deg, масштаб x2 */ transform: matrix(1.732, 0.5, -0.5, 1.732, 40, 20); /* поменяли только a и d */ } - собственная проверка показала, что так съезжают И угол поворота (получится около 16 градусов, а не 30), И масштаб (около 1.8 раза, а не 2) - менять нужно было все четыре числа a, b, c, d сразу.

matrix3d(): когда нужны все шестнадцать чисел

matrix() устроен так, что описывает только плоские, двумерные превращения. Как только в цепочке transform появляется что-то по-настоящему трёхмерное - rotateX(), rotateY(), translateZ(), translate3d() или сама функция perspective() - браузер переходит на matrix3d(): те же шесть чисел вырастают до шестнадцати, потому что описывается уже трёхмерная матрица 4x4. Собственная проверка подтвердила: rotateY(45deg) и translateZ(10px) в getComputedStyle возвращаются именно как matrix3d(...), а не matrix(...), даже если в коде была написана одна простая функция. Формально matrix() - это просто частный случай matrix3d() с нулями и единицами в "третьем измерении". Но matrix3d() сам по себе не гарантирует, что элемент действительно будет выглядеть объёмным: собственная проверка показала, что rotateY(50deg) без свойства perspective на родительском элементе выглядит просто как плоское горизонтальное сжатие, без всякого ощущения глубины - настоящий наклон появляется, только если у родителя задан perspective (или использована функция perspective() прямо внутри transform).

Из истории

Обычные, плоские CSS-трансформации появились в 2007 году, а вот трёхмерные - позже и отдельно: в официальном блоге WebKit 16 июля 2009 года Саймон Фрейзер (Simon Fraser) объявил о поддержке 3D-трансформаций в WebKit на Mac OS X, уточнив, что на iPhone они были доступны уже с версии OS 2.0 - то есть ещё в 2008 году. Оригинальный анонс в блоге WebKit.

.card { transform: perspective(600px) rotateY(30deg); } - perspective() прямо внутри transform - блок наклоняется по-настоящему объёмно.

Неправильное ожидание - что rotateY() сам по себе даёт объёмный эффект:

.card { transform: rotateY(30deg); } - без perspective блок просто визуально сжимается по горизонтали, как будто применили scaleX() - никакой глубины не видно.

Частые ошибки новичков

ОшибкаЧто происходитКак исправить
Пытаться "увеличить масштаб" в готовой matrix(), меняя только числа a и d Если в матрице уже есть поворот (b и c не равны 0), угол поворота и итоговый масштаб съезжают одновременно - результат не совпадает ни с ожидаемым углом, ни с размером Собирать трансформацию через отдельные функции translate/rotate/scale и не редактировать сырые числа матрицы вручную
Путать порядок параметров matrix(a, b, c, d, tx, ty) Сдвиг (tx, ty) - это всегда два ПОСЛЕДНИХ числа, а не первые - первые четыре отвечают за поворот и масштаб Сверяться с формулой matrix(scaleX(), skewY(), skewX(), scaleY(), translateX(), translateY()) перед ручной правкой
Думать, что matrix3d() сам по себе даёт объёмный эффект Без perspective на родителе (или perspective() в самом transform) rotateX()/rotateY() выглядят как плоское сжатие, без ощущения глубины Всегда задавать perspective - на родительском элементе или прямо внутри transform
Удивляться, что getComputedStyle().transform показывает matrix3d(...) с 16 числами, хотя в CSS был написан один простой rotateX() или translateZ() Браузер всегда "сворачивает" любую трёхмерную функцию в matrix3d() - это нормальное внутреннее представление, а не ошибка Воспринимать matrix3d() в DevTools как норму и, если нужно узнать исходные значения, смотреть в саму CSS-таблицу стилей, а не в computed-стиль

Шпаргалка

ЗаписьЧто означает
matrix(a, b, c, d, tx, ty)6 чисел для 2D: a, d - масштаб/косинус, b, c - наклон/синус, tx, ty - сдвиг
rotate(45deg)matrix(0.707, 0.707, -0.707, 0.707, 0, 0)
translate(40px, 25px)matrix(1, 0, 0, 1, 40, 25)
scale(2, 3)matrix(2, 0, 0, 3, 0, 0)
matrix3d(16 чисел)3D-версия matrix() - появляется, как только в цепочке есть rotateX/Y, translateZ, perspective и т.п.
transform-origin (урок 13)Не входит в саму матрицу - браузер применяет точку трансформации отдельно при отрисовке

Коротко: отвечаем на вопросы

Почему в getComputedStyle().transform всегда получается matrix3d(), хотя в CSS был написан простой translate3d() с rotateX/Y?

Потому что браузер всегда нормализует любую трёхмерную трансформацию в единую матрицу 4x4 - matrix3d() с 16 числами - независимо от того, сколько отдельных функций было написано в исходном CSS. Достать обратно исходные читаемые значения (например, конкретный сдвиг по Z) из готовой матрицы просто так нельзя - нужно либо хранить эти значения отдельно в JavaScript, либо разбирать матрицу вручную по формулам.

Я применил transform: rotateY(-25deg) к картинке, но она просто сжалась по горизонтали, а не наклонилась в перспективе. Почему?

Потому что одного rotateY() недостаточно для объёмного эффекта - без свойства perspective (на родительском элементе или через функцию perspective() прямо в transform) браузеру не из чего строить перспективу, и поворот вокруг вертикальной оси выглядит просто как плоское сжатие. Нужно добавить, например, perspective: 600px на обёртку или переписать как transform: perspective(600px) rotateY(-25deg).

Категория
Поделиться в социальных сетях

Отправить комментарий

0 Комментарии

Отправить комментарий (0)

#buttons=(Хорошо) #days=(20)

Мы используем файлы cookie для улучшения работы сайта. Подробнее
Хорошо
×