Матрица преобразований

Влад Мержевич

Многие веб-разработчики игнорируют матрицу преобразований, полагая её слишком сложной для понимания и используя взамен простейшие функции для трансформации. И совершенно зря, матрица преобразований обладает широкими возможностями, вдобавок, в том или ином виде поддерживаются всеми браузерами, а значит её применение даёт кроссбраузерный код. Так что давайте разбираться, что это такое и как использовать матрицу преобразований на практике.

Трансформация

Сама матрица преобразований предназначена для вычисления новых координат элемента с целью его трансформации. При этом соблюдается условие, что линии всегда остаются параллельными, поэтому в качестве трансформации допустимы поворот, масштабирование, наклон и изменение положения, но никак не перспектива или нечто подобное. На рис. 1 показаны допустимые и невозможные преобразования, сделанные с помощью матриц.

Исходный элемент Поворот Наклон А вот так сделать нельзя
Исходный элемент Поворот Наклон А вот так сделать нельзя

Рис. 1. Трансформация элемента

Сама матрица имеет размер 3х3 и в общем виде записывается так:

Матрица преобразований

Иногда для простоты третью колонку опускают, поскольку она не оказывает влияния на конечный результат. Новые координаты каждой точки элемента после преобразования с помощью матрицы вычисляются по следующей формуле:

Формула преобразования

Роль каждого коэффициента матрицы представлена в табл. 1.

Табл. 1. Коэффициенты матрицы преобразований
Коэффициент Преобразование Описание
a Изменение размера по горизонтали Изменение масштаба по горизонтали. Значение больше 1 расширяет элемент, меньше 1, наоборот, сжимает.
b Наклон по вертикали Наклон по горизонтали. Положительное значение наклоняет влево, отрицательное вправо.
c Наклон по горизонтали Наклон по вертикали. Положительное значение наклоняет вверх, отрицательное вниз.
d Изменение размера по вертикали Изменение масштаба по вертикали. Значение больше 1 расширяет элемент, меньше 1 — сжимает.
tx Смещение по горизонтали в пикселах Смещение по горизонтали в пикселах. Положительное значение сдвигает элемент вправо на заданное число пикселов, отрицательное значение сдвигает влево.
ty Смещение по вертикали в пикселах Смещение по вертикали в пикселах. При положительном значении элемент опускается на заданное число пикселов вниз или вверх при отрицательном значении.

Для наглядности действие каждого коэффициента вы можете проверить на данной форме (в IE не работает).

Ёжик

Матрица преобразований в браузерах

Для трансформации элемента применяется стилевое свойство transform, которое принимает в качестве значения ключевое слово matrix, внутри скобок перечисляются коэффициенты нашей матрицы преобразований.

transform: matrix(a, c, b, d, tx, ty)

Обратите внимание на порядок коэффициентов, это имеет принципиальное значение.

Как обычно, разные браузеры со свойствами CSS3 работают по своему, понимая их только с префиксами, поэтому приходится дублировать одну строку несколько раз.

-moz-transform: matrix(a, c, b, d, tx, ty); /* Firefox 3.5+ */ 
-webkit-transform: matrix(a, c, b, d, tx, ty); /* Safari 3.1+ и Chrome 2.0+ */
-o-transform: matrix(a, c, b, d, tx, ty); /* Opera 10.5+ */
-ms-transform: matrix(a, c, b, d, tx, ty); /* IE 9.0 */
filter: progid:DXImageTransform.Microsoft.Matrix(M11=a, M12=b, M21=c, M22=d, 
        Dx=tx, Dy=ty); /* IE 5.5+ */

Если вам нужна поддержка Internet Explorer до версии 9.0, тогда придётся использовать нестандартное свойство filter, имеющее свой особый синтаксис.

Единичная матрица

Если в матрице коэффициенты a и d равны 1, а остальные элементы матрицы нулевые, то такая матрица называется единичной. Эта матрица применяется по умолчанию, поскольку не приводит к какой-либо трансформации элемента. Так что если необходимо произвести только один вид преобразований, единичную матрицу надо брать в качестве основы.

Единичная матрица

Масштаб по горизонтали

Чтобы увеличить размер элемента, допустим, в два раза по горизонтали, коэффициент a следует установить равным 2, а остальные коэффициенты оставить как в единичной матрице.

Масштабирование

Считаем новые координаты:

x' = 2*x + 0*y + 0
y' = 0*x + 1*y + 0

И окончательно

x' = 2x
y' = y

Код для масштабирования показан в примере 1.

Пример 1. Масштабирование

<!DOCTYPE html>
 <html>
  <head>
  <meta charset="utf-8">
  <title>transform</title>
  <style>
   .t {
    background: #fc0;
    padding: 10px;
    width: 300px;
    -moz-transform: matrix(2, 0, 0, 1, 0, 0);
    -webkit-transform: matrix(2, 0, 0, 1, 0, 0);
    -o-transform: matrix(2, 0, 0, 1, 0, 0);
    -ms-transform: matrix(2, 0, 0, 1, 0, 0);
   }
  </style>
 </head>
 <body>
  <div class="t">
   <p>То, что делает армию при встрече с противником непобедимой, 
      это правильный бой и маневр.</p>
   <p>Сунь-Цзы. Искусство войны. Пер. Н. Конрад.</p>
  </div>
 </body>
</html>

Отражение

Для отражение элемента по горизонтали следует установить a=-1, по вертикали d=-1 или эти значения одновременно для отражения одним разом по горизонтали и вертикали.

Отражение

В примере 2 показано отражение рисунка по вертикали.

Пример 2. Отражение

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
  <title>transform</title>
  <style>
   .t {
    -moz-transform: matrix(1, 0, 0, -1, 0, 0);
    -webkit-transform: matrix(1, 0, 0, -1, 0, 0);
    -o-transform: matrix(1, 0, 0, -1, 0, 0);
    -ms-transform: matrix(1, 0, 0, -1, 0, 0);
    opacity: 0.3;
   }
  </style>
 </head>
 <body>
  <p><img src="images/igels.png" alt="Ёжик"><br>
  <img src="images/igels.png" alt="Отражение" class="t"></p>
 </body>
</html>

Наклон

За наклон отвечают коэффициенты b и c, которые и влияют на вид элемента. Давайте установим b=1 и посмотрим, какие преобразования получатся.

Наклон

x' = 1*x + 0*y + 0
y' = 1*x + 1*y + 0

x' = x
y' = x + y

Таким образом, меняется только координата y, которая увеличивается на значение x, что и приводит к наклону элемента. В примере 3 используется отрицательное значение коэффициента b для наклона вправо.

Пример 3. Наклон

<!DOCTYPE html>
<html>
 <head>
  <meta charset="utf-8">
  <title>transform</title>
  <style>
   .t {
    background: #fc0;
    padding: 10px;
    width: 400px;
    -moz-transform: matrix(1, 0, -0.5, 1, 0, 0);
    -webkit-transform: matrix(1, 0, -0.5, 1, 0, 0);
    -o-transform: matrix(1, 0, -0.5, 1, 0, 0);
    -ms-transform: matrix(1, 0, -0.5, 1, 0, 0);
   }
  </style>
 </head>
 <body>
  <div class="t">
   <p>То, что делает армию при встрече с противником непобедимой, 
   это правильный бой и маневр.</p>
   <p>Сунь-Цзы. Искусство войны. Пер. Н. Конрад.</p>
  </div>
 </body>
</html>

Поворот

Поворот является комбинацией масштабирования и наклона, но чтобы сохранить исходные пропорции элемента преобразования должны подчиняться строгим вычислениям с использование синусов и косинусов.

Поворот

Сам поворот происходит по часовой стрелке, α задаёт угол поворота в градусах.

Перемещение

За сдвиг элемента по горизонтали отвечает коэффициент tx, а по вертикали ty. Значением выступает число пикселов, Firefox, кроме того, единственный браузер, который поддерживает и другие единицы, например, em.

Перемещение само по себе применяется довольно редко из-за того, что в CSS для этого есть множество других средств, например позиционирование или отступы.

Резюме

Несмотря на некоторый ореол загадочности вокруг матрицы преобразований, на деле это довольно простой и эффективный инструмент трансформации в CSS. Конечно, применять матрицы нужно не всегда, например, для поворота есть готовая функция rotate, более простая и понятная в использовании, чем тригонометрические вычисления. Тем не менее, для каких-то случаев вроде отражения элементов матрица преобразований просто незаменима.

Не выкладывайте свой код напрямую в комментариях, он отображается некорректно. Воспользуйтесь сервисом cssdeck.com или jsfiddle.net, сохраните код и в комментариях дайте на него ссылку. Так и результат сразу увидят.