Функции CSS-трансформации

С помощью этого набора разнообразных функций можно исказить реальность. Хотя бы в пределах веб-страницы 😉

Время чтения: 8 мин

Кратко

Секция статьи "Кратко"

Трансформации к элементу применяются при помощи свойства transform. А значением для этого свойства являются функции трансформации.

Пример

Секция статьи "Пример"
        
          
          .element {  transform: translateX(120px);}
          .element {
  transform: translateX(120px);
}

        
        
          
        
      

Как это понять

Секция статьи "Как это понять"

Часто бывает необходимо каким-то образом трансформировать визуальное представление элемента (масштабировать, повернуть, переместить) и при этом никак не затронуть соседние элементы в документе. Для подобных преобразований используется свойство transform. В качестве значения выступают различные функции трансформации: rotate, translate, scale, skew и другие.

Открыть демо в новой вкладке

Функции трансформации можно условно разбить на несколько групп.

Функции перемещения

Секция статьи "Функции перемещения"

translate(X, Y)

Секция статьи "translate(X, Y)"

Функция используется для смещения элемента вверх-вниз или влево-вправо. В целом, ту же работу выполняют CSS-свойства top, right, bottom, left — например, для абсолютно (position: absolute) или относительно (position: relative) спозиционированных элементов. Но есть ряд важных отличий: элемент позиционируется относительно соответствующих сторон родителя. То есть left: 20px сместит элемент на 20 пикселей относительно левой границы родителя, а translate(20px) сместит элемент вправо относительно того места, где тот находился до трансформации. В целом, позиционирование и translate прекрасно сочетаются друг с другом. Позиционирование лучше использовать для изначального расположения элемента на странице, а translate применять, если нужно добавить анимации движения.

Функция принимает два параметра: первый параметр отвечает за смещение вправо-влево, а второй параметр — вверх-вниз. Если передать только один параметр, тогда смещение будет только вправо-влево. Мы можем использовать любые единицы измерения расстояния из CSS, например, абсолютные 10px или относительные 50%. Абсолютное значение используется «как есть»: элемент сместится на 10 пикселей. Относительное значение считается относительно размеров самого элемента. При указании 50% элемент сместится на половину собственной ширины или высоты.

translateX(X), translateY(Y), translateZ(Z)

Секция статьи "translateX(X), translateY(Y), translateZ(Z)"

Когда нужно сместить элемент вдоль конкретной оси, можно применить соответствующие функции трансформации.

translate3d(X, Y, Z)

Секция статьи "translate3d(X, Y, Z)"

Если нужно сместить элемент по всем трём осям, можно всё собрать в кучку и использовать эту функцию.

Функции масштабирования

Секция статьи "Функции масштабирования"

scale(X, Y)

Секция статьи "scale(X, Y)"

Функция для масштабирования элемента. Значения X и Y — это положительные числа, либо 0. Если в функцию передать 0, то элемент не будет виден. Единица соответствует нормальному масштабу. Числа от 0 до 1 — это уменьшенный масштаб. Числа больше единицы — увеличенный масштаб. Например, чтобы визуально увеличить элемент в 2 раза, нужно написать transform: scale(2).

В отличие от translate, один параметр в функции scale работает несколько иначе. scale(2) — это то же самое, что scale(2, 2), то есть одно число указывает на пропорциональное масштабирование по обеим осям одновременно.

scaleX(X), scaleY(Y), scaleZ(Z)

Секция статьи "scaleX(X), scaleY(Y), scaleZ(Z)"

Используем, когда необходимо растягивать или сжимать элемент только по горизонтали, вертикали или третьей оси Z.

scale3d(X, Y, Z)

Секция статьи "scale3d(X, Y, Z)"

Если нужно масштабировать элемент по всем трём осям, можно всё собрать в кучку и использовать эту функцию.

Функции наклона

Секция статьи "Функции наклона"

skewX(X), skewY(Y)

Секция статьи "skewX(X), skewY(Y)"

Функции выполняют сдвиг одной стороны элемента относительно противолежащей. В результате элемент как бы наклоняется. Величина наклона зависит от положения точки применения трансформаций (transform-origin) и числа градусов, заданных в параметрах. skewX сдвигает верхнюю сторону элемента относительно нижней. skewY — правую сторону относительно левой.

Функции поворота

Секция статьи "Функции поворота"

rotateX(X), rotateY(Y), rotateZ(Z)

Секция статьи "rotateX(X), rotateY(Y), rotateZ(Z)"

Кроме сдвига или наклона, элемент можно вращать. В функцию передаём единицы измерения углов (deg, rad, turn), например 45deg или 0.5turn. Обратите внимание, что обычное вращение элемента на странице — это вращение относительно оси Z. Если мы хотим вращать элемент относительно других осей, то нужно не забывать про перспективу. С ней повороты относительно X или Y будут выглядеть максимально естественно.

rotate(Z)

Секция статьи "rotate(Z)"

Функция аналогична rotateZ(Z). Чтобы не запоминать ось для типового вращения элемента, мы можем использовать просто слово rotate.

rotate3d(X, Y, Z)

Секция статьи "rotate3d(X, Y, Z)"

Если нужно повернуть элемент по всем трём осям, можно всё собрать в кучку и использовать эту функцию.

Прочие функции

Секция статьи "Прочие функции"

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

Секция статьи "matrix(a, b, c, d, tx, ty)"

Выше мы упомянули несколько функций трансформации. Каждая выполняет какое-то одно небольшое действие. matrix() — это функция, которой можно описать любую трансформацию в плоскости экрана. Она использует матричные преобразования и может заменить собой все вышеописанные функции. Но при этом она очень сложно читается. Например, глядя на функцию matrix(0.707107, 0.707107, -0.707107, 0.707107, -0.707107, 34.6482) невозможно сразу точно определить, что она аналогична записи rotate(45deg) translate(24px, 25px). Зачем же она нужна, такая сложная, если проще описать трансформации соответствующими функциями? Ну например, с её помощью можно писать сложные динамические анимации. Популярные JS-библиотеки для анимации «под капотом» используют как раз матричные преобразования, а не конкретные функции трансформации.

matrix3d(a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3, a4, b4, c4, d4)

Секция статьи "matrix3d(a1, b1, c1, d1, a2, b2, c2, d2, a3, b3, c3, d3, a4, b4, c4, d4)"

Если нам нужно произвести трансформации в трёхмерном пространстве, а не в плоскости экрана, то нужно использовать эту функцию. Она ещё более сложна в понимании, и вряд ли кто-то вообще пишет её руками.

perspective(Z)

Секция статьи "perspective(Z)"

Несмотря на то, что экран плоский, у нас всё равно есть возможность перемещать элемент вдоль оси Z. Она направлена перпендикулярно плоскости экрана в сторону пользователя. Если мы используем translateZ просто так, то никакого перемещения ближе или дальше мы не увидим. Чтобы было ощущение движения к нам или от нас, элемент должен становиться крупнее или мельче. Стул, который стоит рядом с нами, будет визуально крупнее, чем стул, стоящий в конце комнаты. Эта разница в размерах — следствие перспективы. Элемент на экране может вести себя подобно объектам в реальном мире и менять размер при перемещении к нам или от нас. Чтобы это заработало, нужно элементу задать свойство perspective. Это свойство необходимо применять при любых трансформациях, выходящих из плоскости экрана.

Функция perspective() принимает один параметр — расстояние до точки схождения перспективы. Плоскость экрана принимается за начало координат. Например, запись perspective(500px) означает, что точка схождения перспективы находится как бы на расстоянии 500 пикселей вглубь от плоскости экрана.

Подсказки

Секция статьи "Подсказки"

💡 Можно применять сразу несколько функций трансформации:

        
          
          .element {  transform: translate(20px, 20px) skew(20deg);}
          .element {
  transform: translate(20px, 20px) skew(20deg);
}

        
        
          
        
      

💡 Если среди значений есть функция perspective(), то она должна быть первой среди всех значений:

Неправильно:

        
          
          .element {  transform: translate3d(10px, 0, 20px) rotateY(3deg) perspective(500px);}
          .element {
  transform: translate3d(10px, 0, 20px) rotateY(3deg) perspective(500px);
}

        
        
          
        
      

Правильно:

        
          
          .element {  transform: perspective(500px) translate3d(10px, 0, 20px) rotateY(3deg);}
          .element {
  transform: perspective(500px) translate3d(10px, 0, 20px) rotateY(3deg);
}

        
        
          
        
      

💡 В последних версиях спецификации появились отдельные CSS-свойства для трансформаций. Это rotate, translate и scale. Если раньше мы писали комплексные трансформации, применяя несколько функций, то теперь каждую трансформацию можем описать отдельным свойством:

        
          
          .transform-function {  transform: translate(100px, 100px) rotate(180deg) scale(2);}.individual-transforms {  translate: 100px 100px;  rotate: 180deg;  scale: 2;}
          .transform-function {
  transform: translate(100px, 100px) rotate(180deg) scale(2);
}

.individual-transforms {
  translate: 100px 100px;
  rotate: 180deg;
  scale: 2;
}

        
        
          
        
      

Оба этих способа записи выполнят одни и те же трансформации, но у них есть ряд принципиальных отличий. Самое главное — используя индивидуальные свойства, мы можем создавать классы-модификаторы без опасения перекрыть всё свойство transform:

        
          
          .element {  transform: translateX(20px) rotate(90deg);}.mid-scale {  scale: 1.5;}
          .element {
  transform: translateX(20px) rotate(90deg);
}

.mid-scale {
  scale: 1.5;
}

        
        
          
        
      

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

        
          
          .element {  transform: translateX(20px) rotate(90deg);}.mid-scale {  transform: scale(1.5);}
          .element {
  transform: translateX(20px) rotate(90deg);
}

.mid-scale {
  transform: scale(1.5);
}

        
        
          
        
      

Добавив этот класс к элементу, мы просто рискуем перекрыть любое свойство transform, заданное до этого.

💡 При использовании свойства transform результирующая трансформация вычисляется с учётом порядка функций. Например, transform: rotate(15deg) translateX(100px) translateY(30px) и transform: translateX(100px) translateY(30px) rotate(15deg); дадут разный конечный результат:

Открыть демо в новой вкладке

Если же мы используем индивидуальные свойства, результат будет одинаковым вне зависимости от порядка свойств:

Открыть демо в новой вкладке

Второй пример нужно смотреть либо в Firefox, либо в Chrome Canary.

На практике

Секция статьи "На практике"

Саша Патлух советует

Секция статьи "Саша Патлух советует"

🛠 Полезное знание при работе с функциями трансформации из JavaScript.

Если мы вычисляем значение функции трансформации, заданной в CSS, методом getComputedStyle(), получим матрицу преобразований. А в случае получения значения из свойства style по ключу — получим строку с описанием функции трансформации.

Допустим, на странице есть div с такой трансформацией, описанной в CSS:

        
          
          div {  transform: translate(200px);}
          div {
  transform: translate(200px);
}

        
        
          
        
      

Вычисление из JS методом getComputedStyle() вернёт значение matrix(1, 0, 0, 1, 200, 0):

        
          
          const element = document.querySelector('div');console.log(getComputedStyle(element).transform);
          const element = document.querySelector('div');
console.log(getComputedStyle(element).transform);

        
        
          
        
      

Но если стиль задан инлайном в HTML,

        
          
          <div style="transform: translate(200px);"></div>
          <div style="transform: translate(200px);"></div>

        
        
          
        
      

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

Код ниже вернёт строку translate(200px)

        
          
          const element = document.querySelector('div');console.log(element.style.transform);
          const element = document.querySelector('div');
console.log(element.style.transform);