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

Вместе с CSS3 появились новые способы позиционирования и изменения элементов. В настоящее время основные техники вёрстки могут быть пересмотрены с альтернативными методами для размера, положения и изменения элементов. Все эти новые техники стали возможными благодаря свойству transform.

Свойство transform поставляется в двух разных наборах — двумерных и трёхмерных. В каждом из них есть свои индивидуальные свойства и значения.

В этом уроке мы рассмотрим как двумерные, так и трёхмерные преобразования. Вообще говоря, поддержка браузера для свойства transform не велика, но она становится всё лучше с каждым днем. Для большей поддержки рекомендуются вендорные префиксы, однако вам может понадобиться загрузить последнюю версию Chrome, чтобы увидеть все эти преобразования в действии.

Синтаксис transform

Фактический синтаксис для свойства transform достаточно прост и включает свойство transform, за которым идёт значение. Значение определяет тип трансформации, внутри скобок которого следует определённая величина.

div {
  -webkit-transform: scale(1.5);
     -moz-transform: scale(1.5);
       -o-transform: scale(1.5);
          transform: scale(1.5);
}

Обратите внимание, что свойство transform включает в себя несколько вендорных префиксов, чтобы получить наилучшую поддержку во всех браузерах. Декларация без префикса идёт последней и чтобы переписать версии с префиксом браузер должен полностью поддерживать свойство transform.

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

Двумерная трансформация

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

2d rotate

Свойство transform принимает несколько разных значений. Значение rotate обеспечивает возможность поворота элемента от 0 до 360 градусов. Положительное значение поворачивает элемент по часовой стрелке, а использование отрицательного значения поворачивает элемент против часовой стрелки. По умолчанию точкой поворота является центр элемента, 50% 50%, по горизонтали и вертикали. Позже мы обсудим как вы можете изменить эту точку поворота.

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>

CSS

.box-1 {
  transform: rotate(20deg);
}
.box-2 {
  transform: rotate(-55deg);
}

Демонстрация rotate

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

2d scale

Использование значения scale в свойстве transform позволяет изменить визуальный размер элемента. Значение масштаба по умолчанию равно 1, поэтому любое значение от .99 до .01 визуально уменьшает элемент, в то время как любое значение больше или равное 1.01 визуально увеличивает элемент.

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>

CSS

.box-1 {
  transform: scale(.75);
}
.box-2 {
  transform: scale(1.25);
}

Демонстрация scale

Можно масштабировать только высоту или ширину элемента, используя значения scaleX и ScaleY. Значение scaleX будет масштабировать ширину элемента, в то время как значение ScaleY будет масштабировать его высоту. Для масштабирования высоты и ширины элемента, но с разными размерами, могут быть одновременно установлены значения по оси х и у. Для этого используя декларацию scale, задав сперва значение по оси x, затем через запятую значение по оси y.

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>
<figure class="box-3">Блок 3</figure>

CSS

.box-1 {
  transform: scaleX(.5);
}
.box-2 {
  transform: scaleY(1.15);
}
.box-3 {
  transform: scale(.5, 1.15);
}

Демонстрация множественного масштабирования

2d translate

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

Как и со значением scale, чтобы одновременно установить значения по осям x и y, воспользуйтесь значением translate и сперва укажите значение по оси х, затем через запятую значение по оси y.

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

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>
<figure class="box-3">Блок 3</figure>

CSS

.box-1 {
  transform: translateX(-10px);
}
.box-2 {
  transform: translateY(25%);
}
.box-3 {
  transform: translate(-10px, 25%);
}

Демонстрация translate

2d skew

Последнее значение skew в группе transform используется для искажения элементов по горизонтальной оси, вертикальной оси или двум осям сразу. Синтаксис очень похож на значения scale и translate. Применение значения skewX деформирует элемент по горизонтальной оси, в то время как значение skewY деформирует элемент по вертикальной оси. Чтобы исказить элемент по двум осям, используется значение skew, сперва задаётся значение по оси х, затем через запятую значение по оси у.

Значение skew измеряется в градусах. Единицы длины, такие как пиксели или проценты, здесь не применимы.

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>
<figure class="box-3">Блок 3</figure>

CSS

.box-1 {
  transform: skewX(5deg);
}
.box-2 {
  transform: skewY(-20deg);
}
.box-3 {
  transform: skew(5deg, -20deg);
}

Демонстрация skew

Комбинация трансформаций

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

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

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>

CSS

.box-1 {
  transform: rotate(25deg) scale(.75);
}
.box-2 {
  transform: skew(10deg, 20deg) translateX(20px);
}

Демонстрация комбинации транформаций

За каждой трансформацией также стоит матрица, явно определяющая поведение transform. Использование значений rotate, scale, transition и skew обеспечивает простой путь задать эту матрицу. Тем не менее, если вы расположены к математике и предпочитаете глубже погрузиться в преобразования, попробуйте свои силы в использовании значения matrix.

Демонстрация двумерного куба

HTML

<div class="cube">
  <figure class="side top">1</figure>
  <figure class="side left">2</figure>
  <figure class="side right">3</figure>
</div>

CSS

.cube {
  position: relative;
}
.side {
  height: 95px;
  position: absolute;
  width: 95px;
}
.top {
  background: #9acc53;
  transform: rotate(-45deg) skew(15deg, 15deg);
}
.left {
  background: #8ec63f;
  transform: rotate(15deg) skew(15deg, 15deg) translate(-50%, 100%);
}
.right {
  background: #80b239;
  transform: rotate(-15deg) skew(-15deg, -15deg) translate(50%, 100%);
}

Точка трансформации

Как упоминалось ранее, по умолчанию точкой трансформации является центр элемента, 50% по горизонтали и 50% по вертикали. Чтобы изменить это положение, может быть использовано свойство transform-origin.

Свойство transform-origin может принимать одно или два значения. Когда задано только одно значение, то оно используется для горизонтальной и вертикальной осях. Если указаны два значения, то первое применяется для горизонтальной оси, а второе для вертикальной.

Отдельно значения похожи на позиционирование фонового изображения с помощью размера или ключевых слов. Таким образом, 0 0 аналогично значению top left, а 100% 100% то же самое, что и bottom right. Более конкретные значения также могут быть установлены, к примеру, 20px 50px задаст исходную точку элемента как 20 пикселей от края и 50 пикселей вниз.

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>
<figure class="box-3">Блок 3</figure>
<figure class="box-4">Блок 4</figure>

CSS

.box-1 {
  transform: rotate(15deg);
  transform-origin: 0 0;
}
.box-2 {
  transform: scale(.5);
  transform-origin: 100% 100%;
}
.box-3 {
  transform: skewX(20deg);
  transform-origin: top left;
}
.box-4 {
  transform: scale(.75) translate(-10px, -10px);
  transform-origin: 20px 50px;
}

Демонстрация transform-origin

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

Перспектива

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

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

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

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

HTML

<figure class="box">Блок 1</figure>
<figure class="box">Блок 2</figure>
<figure class="box">Блок 3</figure>

CSS

.box {
  transform: perspective(200px) rotateX(45deg);
}

Демонстрация значения perspective

В следующем примере показано несколько элементов рядом друг с другом, все преобразованы с использованием одной перспективы, добавленной с помощью свойства perspective к их прямому родительском элементу.

HTML

<div class="group">
  <figure class="box">Блок 1</figure>
  <figure class="box">Блок 2</figure>
  <figure class="box">Блок 3</figure>
</div>

CSS

.group {
  perspective: 200px;
}
.box {
  transform: rotateX(45deg);
}

Демонстрация свойства perspective

Глубина перспективы

В качестве значения перспективы может быть задано none или длина. Значение none отключает любую перспективу, в то время как значение длины установит глубину перспективы. Чем выше значение, тем дальше вид перспективы, создавая тем самым перспективу довольно низкой интенсивности и небольшое трёхмерное изменение. Низкое значение приближает вид перспективы, тем самым создавая перспективу высокой интенсивности и большое трёхмерное изменение.

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

HTML

<figure class="box-1">Box 1</figure>
<figure class="box-2">Box 2</figure>

CSS

.box-1 {
  transform: perspective(100px) rotateX(45deg);
}
.box-2 {
  transform: perspective(1000px) rotateX(45deg);
}

Демонстрация глубины перспективы

Начало перспективы

Как и в случае установки transform-origin вы можете также задать perspective-origin. Те же значения, используемые для свойства transform-origin, могут быть использованы в свойстве perspective-origin и оказывают такое же влияние на элемент. Есть большая разница между этими двумя подходами — точка трансформации определяет координаты, используемые для расчёта изменения трансформации, тогда как начало перспективы определяет координаты точки схода преобразования.

HTML

<div class="original original-1">
  <figure class="box">Блок 1</figure>
</div>
<div class="original original-2">
  <figure class="box">Блок 2</figure>
</div>
<div class="original original-3">
  <figure class="box">Блок 3</figure>
</div>

CSS

.original {
  perspective: 200px;
}
.box {
  transform: rotateX(45deg);
}
.original-1 {
  perspective-origin: 0 0;
}
.original-2 {
  perspective-origin: 75% 75%;
}
.original-3 {
  perspective-origin: 20px 40px;
}

Демонстрация perspective-origin

Трёхмерная трансформация

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

3d rotate

До сих пор мы обсуждали, как повернуть объект по часовой или против часовой стрелки на плоской поверхности. С помощью трёхмерных преобразований мы можем вращать элемент вокруг любых осей. Для этого мы используем три новые значения, включая rotateX, rotateY н rotateZ.

Значение rotateX позволяет поворачивать элемент вокруг оси х, как будто он сгибается пополам по горизонтали. Значение rotateY позволяет поворачивать элемент вокруг оси у, как будто он сгибается пополам по вертикали. И, наконец, значение rotateZ позволяет вращать элемент вокруг оси z.

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

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>
<figure class="box-3">Блок 3</figure>

CSS

.box-1 {
  transform: perspective(200px) rotateX(45deg);
}
.box-2 {
  transform: perspective(200px) rotateY(45deg);
}
.box-3 {
  transform: perspective(200px) rotateZ(45deg);
}

Демонстрация 3d rotate

3d scale

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

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>

CSS

.box-1 {
  transform: perspective(200px) scaleZ(1.75) rotateX(45deg);
}
.box-2 {
  transform: perspective(200px) scaleZ(.25) rotateX(45deg);
}

Демонстрация 3d scale

3D translate

Элементы могут также передвигаться по оси z с помощью значения translateZ. Отрицательное значение будет толкать элемент дальше по оси z, что приводит к уменьшению элемента. Положительное значение будет тянуть элемент ближе по оси z, что приводит к увеличению элемента.

Хотя это может показаться очень похоже на двумерную трансформацию scale, на самом деле у них есть различия. Преобразование происходит по оси z, а не по осям х или у. При работе с трёхмерными преобразованиями возможность переместить элемент по оси z даёт серьёзные преимущества, как при построении куба в примере ниже.

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>

CSS

.box-1 {
  transform: perspective(200px) translateZ(-50px);
}
.box-2 {
  transform: perspective(200px) translateZ(50px);
}

Демонстрация 3d translate

3D skew

skew является единственной двумерной трансформацией, которая не может быть преобразована в трёхмерном масштабе. Элементы могут быть наклонены по осям х и у, затем преобразованы трёхмерно как хотелось бы, но они не могут быть наклонены по оси z.

Сокращённые трёхмерные трансформации

Как и в случае комбинаций двумерных преобразований, есть также значения для записи сокращённых трёхмерных преобразований. Эти значения включают rotate3d, scale3d, transition3d и matrix3d. Эти свойства требуют чуть больше математики, а также глубокого понимания матриц, стоящих за каждой трансформацией. Если вам интересно чуть глубже взглянуть на это, тогда вперёд!

transform-style

В некоторых случаях трёхмерные трансформации будут применяться к элементу, вложенному в родительский элемент, который в свою очередь также трансформируется. В этом случае вложенные преобразованные элементы не будут появляться в своём собственном трёхмерном пространстве. Чтобы позволить вложенным элементам трансформироваться в их собственной трёхмерной плоскости применяется свойство transform-style со значением preserve-3d.

Свойство transform-style должно быть добавлено к родительскому элементу, выше любых вложенных преобразований. Значение preserve-3d позволяет преобразованным дочерним элементам появляться в их собственной трёхмерной плоскости, в то время как значение flat заставляет преобразованные дочерние элементы лежать в двухмерной плоскости.

HTML

<div class="rotate three-d">
  <figure class="box">Блок 1</figure>
</div>
<div class="rotate">
  <figure class="box">Блок 2</figure>
</div>

CSS

.rotate {
  transform: perspective(200px) rotateY(45deg);
}
.three-d {
  transform-style: preserve-3d;
}
.box {
  transform: rotateX(15deg) translateZ(20px);
  transform-origin: 0 0;
}

Демонстрация transform-style

Чтобы увидеть дополнительный пример использования свойства transform-style в действии прочитайте объяснение WebKit.

backface-visibility

При работе с трёхмерными преобразованиями, элементы время от времени трансформируются таким образом, что их поверхность отворачивается от экрана. Это может быть вызвано установкой значения rotateY(180deg), к примеру. По умолчанию эти элементы показываются с обратной стороны. Так что если вы не желаете видеть эти элементы вообще, установите свойство backface-visibility как hidden, и вы спрячете элемент всякий раз, когда он отворачивается от экрана.

Другим значением для backface-visibility является значение по умолчанию visible, оно всегда показывая элемент, независимо от того, в каком направлении он смотрит.

В демонстрации ниже обратите внимание, что второй блок не отображается, поскольку установлена запись backface-visibility: hidden. Свойство backface-visibility имеет более важное значение при использовании анимации.

HTML

<figure class="box-1">Блок 1</figure>
<figure class="box-2">Блок 2</figure>

CSS

.box-1 {
  transform: rotateY(180deg);
}
.box-2 {
  backface-visibility: hidden;
  transform: rotateY(180deg);
}

Демонстрация backface-visibility

Демонстрация трёхмерного куба

HTML

<div class="cube-container">
  <div class="cube">
    <figure class="side front">1</figure>
    <figure class="side back">2</figure>
    <figure class="side left">3</figure>
    <figure class="side right">4</figure>
    <figure class="side top">5</figure>
    <figure class="side bottom">6</figure>
  </div>
</div>

CSS

.cube-container {
  height: 200px;
  perspective: 300;
  position: relative;
  width: 200px;
}
.cube { 
  height: 100%;
  position: absolute;
  transform: translateZ(-100px);
  transform-style: preserve-3d;
  width: 100%;
}
.side {
  background: rgba(45, 179, 74, .3);
  border: 2px solid #2db34a;
  height: 196px;
  position: absolute;
  width: 196px;
}
.front {
  transform: translateZ(100px);
}
.back {
  transform: rotateX(180deg) translateZ(100px);
}
.left {
  transform: rotateY(-90deg) translateZ(100px);
}
.right {
  transform: rotateY(90deg) translateZ(100px);
}
.top {
  transform: rotateX(90deg) translateZ(100px);
}
.bottom {
  transform: rotateX(-90deg) translateZ(100px);
}

Ресурсы и ссылки

Автор: Шэй Хоу
Последнее изменение: 20.02.2024