2.24. CSS3 3D-трансформации

css3-3d-transformCSS3 3D-трансформации создают объемные реалистичные эффекты на веб-страницах.

3D-трансформации работают аналогично с 2D-трансформациями с разницей в том, что элементы могут перемещаться вдоль оси Z, вглубь экрана и из него.

Чтобы активизировать 3D-пространство, нужно установить свойство perspective для родительского контейнера.

CSS3 3D-трансформации элементов

Поддержка браузерами

IE: 10.0
Firefox: 16.0, 10. -moz-
Chrome: 36.0, 12.0 -webkit-
Safari: 4.0 -webkit-
Opera: 23.0, 15.0 -webkit-
iOS Safari: 9, 7.1 -webkit-
Opera Mini:
Android Browser: 44, 4.1 -webkit-
Chrome for Android: 44

See the Pen Beautiful 3D-animation by Elena Nazarova (@nazarelen) on CodePen.

1. Установка 3D-перспективы perspective

Свойство активирует 3D-пространство для элемента. Свойство perspective и функция perspective() добавляют глубину элементу, увеличивая его размеры по оси Z, сам элемент при этом становится визуально меньше. Чем меньше значение, тем ближе Z-пространство к зрителю и тем больше эффект, заданный с помощью свойства transform.

Если 3D-перспектива задается с помощью функции perspective(), 3D-пространство активизируется только для одного элемента. Свойство perspective активирует 3D-пространство внутри элемента, содержащего дочерние трансформированные элементы и применяется к ним. Свойство не наследуется.

perspective
Значения:
длина Задает глубину просмотра, т.е. расстояние по оси Z. Значение может быть любым положительным числом. Если единица измерения не указана, по умолчанию она считается в px. Чем больше значение, тем менее выражен эффект. 0 означает отсутствие перспективы.
none Значение по умолчанию. Означает отсутствие перспективы.
initial Устанавливает значение свойства в значение по умолчанию.
inherit Наследует значение свойства от родительского элемента.

Синтаксис

ul {perspective: 500px;}

li {transform: rotateX(50deg);}
li:hover {transform: perspective(900px) rotate3d(180,-45,0,-135deg);}
perspective-3d
Рис. 1. Примеры разных значений 3D-перспективы

2. Задание точки трансформации для 3D-элемента perspective-origin

Свойство устанавливает точку начала координат для свойства perspective. Значение по умолчанию perspective-origin: 50% 50%;. Позволяет изменять направление трансформации дочернего 3D-элемента. Свойство должно использоваться вместе со свойством perspective для блока-контейнера и свойством transform для дочернего элемента. Не наследуется.

perspective-origin
Значения:
значение по оси X/значение по оси Y Первое значение указывает положение элемента по оси X. Может задаваться в единицах длины, в % или одним из трех ключевых слов: left (эквивалентно 0% по оси X), center (эквивалентно 50% по оси X) или right (эквивалентно 100% по оси X).
Второе значение указывает положение по оси Y. Задается в единицах длины, в % или одним из трех ключевых слов: top (эквивалентно 0% по оси Y), center (эквивалентно 50% по оси Y) или bottom (эквивалентно 100% по оси Y).
initial Устанавливает значение свойства в значение по умолчанию.
inherit Наследует значение свойства от родительского элемента.

Синтаксис

ul {
perspective: 150px;
perspective-origin: 10% 10%;
}
li {transform: rotateX(50deg);}
perspective-origin
Рис. 2. Примеры задания точки трансформации

3. Стиль 3D-преобразований transform-style

Свойство определяет, как вложенные элементы отрисовываются в трехмерном пространстве. Свойство должно использоваться вместе со свойством transform и задается только для вложенных элементов. Не наследуется.

transform-style
Значения:
flat Значение по умолчанию. Все дочерние элементы отображаются плоскими в двухмерной плоскости блока-контейнера.
preserve-3d Располагает элементы в трехмерном пространстве.
initial Устанавливает значение свойства в значение по умолчанию.
inherit Наследует значение свойства от родительского элемента.

Синтаксис

div {
transform: rotateY(60deg);
transform-style: preserve-3d;
}

See the Pen JRodpX by Elena (@html5book) on CodePen.

4. Видимость обратной стороны элемента backface-visibility

Свойство определяет, будет ли видна пользователю обратная сторона преобразованного элемента. У непреобразованного элемента к пользователю обращена передняя сторона. Не наследуется.

backface-visibility
Значения:
visible Значение по умолчанию. Указывает, что обратная сторона видна.
hidden Скрывает обратную сторону элемента.
initial Устанавливает значение свойства в значение по умолчанию.
inherit Наследует значение свойства от родительского элемента.

Синтаксис

div {backface-visibility: hidden;}

See the Pen PGPKKv by Elena (@html5book) on CodePen.

5. Функции 3D-трансформации transform

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

See the Pen EgVvww by Elena (@html5book) on CodePen.

Функция Описание
matrix3d
(n,n,n,n,
n,n,n,n,
n,n,n,n,
n,n,n,n)
Функция задает трехмерное преобразование как однородную матрицу размером 4×4 с шестнадцатью значениями в столбцах. Все другие функции преобразований основаны на данной функции.
translate3d(x,y,z) Функция задает перемещение элемента в 3D-пространстве. Движение происходит по вектору [tx, ty, tz], где tx перемещение вдоль оси X, ty — перемещение вдоль оси Y, а tz — вдоль оси Z. Значения могут задаваться в единицах длины или в %. Отрицательные значения будут перемещать элемент в противоположном направлении.

transform: translate3d(100px, 100px, -200px);
transform: translate3d(50%, -100%, 10%);
transform: translate3d(-100px, -30px, 50px);

translateZ(z) Функция задает перемещение элемента на заданное расстояние в направлении оси Z. Значения могут задаваться в единицах длины или в %. Отрицательные значения будут перемещать элемент в противоположном направлении.

transform: translateZ(300px);
transform: translateZ(-50%);
transform: translateZ(150%);

scale3d(x,y,z) Функция задает операцию трехмерного масштабирования по вектору масштабирования [sx,sy,sz], описываемому тремя параметрами. Отрицательные значения отображают элемент зеркально вдоль трех осей.

transform: scale3d(2, 1, 3);
transform: scale3d(-1, -2, -1);

scaleZ(z) Функция масштабирует элемент в направлении оси Z, делая его больше или меньше. В качестве значения задается число. Результат функции наиболее выражен при совместном использовании с такими функциями, как rotate() и perspective().

transform: scaleZ(3);
transform: scaleZ(-1);

rotate3d(x,y,z,угол) Функция вращает элемент по часовой стрелке относительно трех осей. Элемент поворачивается под углом, задаваемым последним параметром относительно вектора направления [x,y,z]. Отрицательные значения поворачивают элемент против часовой стрелки.

transform: rotate3d(1, 1, 2, 45deg);

rotateX(угол) Функция задает поворот по часовой стрелке под заданным углом относительно оси X.
Функция rotateX(180deg) эквивалентна rotate3d(1,0,0,180deg).

transform: rotateX(30deg);
transform: rotateX(-135deg);

rotateY(угол) Функция задает поворот по часовой стрелке под заданным углом относительно оси Y.
Функция rotateY(180deg) эквивалентна rotate3d(0,1,0,180deg).

transform: rotateY(30deg);
transform: rotateY(-135deg);

rotateZ(угол) Функция задает поворот по часовой стрелке под заданным углом относительно оси Z.
Функция rotateZ(180deg) эквивалентна rotate3d(0,0,1,180deg).

transform: rotateZ(30deg);
transform: rotateZ(-135deg);

perspective(n) Функция меняет перспективу обзора элемента, создавая иллюзию глубины. Чем больше значение функции перспективы, тем дальше от смотрящего расположен элемент. Значение должно быть больше нуля.

transform: perspective(300);
transform: perspective(300px);

initial Устанавливает значение свойства в значение по умолчанию.
inherit Наследует значение свойства от родительского элемента.

Синтаксис

div {transform: rotateX(150deg);}
  • Inveresr.PRO

    Замечательная статья, благодарю!

  • nariaran

    Отличный гайд по 3D трансформации! Спасибо за проделанную работу!

  • Владимир

    Елена, спасибо Вам за труд. Изучил 3Dтрансформацию по вашему уроку, но на практике столкнулся с проблемой: http://codepen.io/VLAD_IMIR/pen/JRxOyB . Блок «earth» оказывается плоским, несмотря на все старания повернуть его по оси Х на 90″. Может подскажите, как это сделать?

    • Пожалуйста!
      Вы взялись сразу за сложный пример, до многих вещей доходишь только в процессе длительной практики и экспериментов со свойствами, так как спецификация не содержит каких-либо значимых пояснений. Сделала пример http://codepen.io/html5book/pen/GjLLgb, чтобы было наглядно, добавила границы для элементов-контейнеров.
      Для элемента earth нужно две дополнительные обёртки: первый блок вращается по оси Z на 360°, второй блок является обёрткой непосредственно для маленького круга.

      • Владимир

        Спасибо

        • Пожалуйста. Лучше экспериментировать с такими прототипами, чтобы понять, как это работает. А потом уже стилизовать внешний вид элементов. Если контейнер поворачиваем под одним углом, то элементы внутри него поворачиваем под противоположным (со знаком минус) значением. Если контейнер вращается в одном направлении, то элемент внутри него вращаем в противоположном, чтобы он всегда был к нам лицом.
          Когда делаете анимацию, обратите внимание, что если для элемента в первоначальном состоянии задана трансформация, например, transform: rotate(45deg), а в @keyframes указываете transform: translateX(100px), то первоначальная трансформация заменяется указанной в @keyframes. Поэтому в @keyframes нужно указывать обе трансформации transform: rotate(45deg) translateX(100px).

  • Илья Цедрик

    https://codepen.io/WEBCedrik/pen/QdWpev Оцените мой первый опыт в анимации))

  • userAlexander

    При задании perspective:1000px; увеличивает дочерние элементы на которых задан transform-style:preserve-3d;
    Кто то пытался решить данную ошибку?

    • Можно ваш пример? Не видя, сложно давать рекомендации.

      • userAlexander

        Конечно, Елен.
        Ссылка на код: http://codepen.io/userAlexander/pen/Qdgvzp
        Ссылка на скриншот ошибки: http://joxi.ru/Dr895GvSgE3pm6.png
        при наложении элементов в фотошопе видно, что есть увеличение элемента, это происходит за счет использования perspective:1000px;

        Ссылка на скриншот того, как должно быть: http://joxi.ru/KAgJ4bkiPJ0k2l.png
        Все в порядке, если не использовать perspective:1000px; но тогда перспектива теряется.

        • Вижу, да, увеличивает при вращении. Мы уже экспериментировали с таким эффектом, посмотрите наш вариант https://codepen.io/html5book/pen/vKraZy, на первый взгляд увеличение не наблюдается.

          • userAlexander

            Да, но у вас же отсутствует свойство perspective, поэтому увеличения не наблюдается.

          • но эффект тот же самый

          • userAlexander

            это все ясно, НО возможно кто то пофиксил данный момент оставив эффект объема, вот, что хотелось бы узнать))

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

          • Может попробовать так:

            .nav__button:hover .nav__button-title{
            	transform:rotateX(90deg) translateY(-50%) scale(.98);
            }
          • userAlexander

            Елена, вы словно видите мой код)))
            Это костыльное решение, так как значение в scale(.98) нужно подстраивать в зависимости от размера элемента с которым работаем)

          • Согласна, костыль. Но вы именно его и просили, так как сломать суть эффекта по- другому не получится.

          • userAlexander

            Нужно еще кого нибудь подключить, коллективный разум способен на многое)

          • )) Просто не используйте перспективу, а только transform-origin и transform (можно matrix3d). И вы получите нужный эффект без каких-либо танцев с бубном.

          • Свойство perspective используется для создания для объёмных фигур, чтобы они не выглядели плоскими. В вашем случае фигура не объёмная, поэтому нет необходимости в использовании этого свойства. И да, перспектива в любом случае будет увеличивать элемент, потому что она создаёт иллюзию глубины. Иллюзия глубины достигается за счёт того, что на заднем плане элемент выглядит меньше, чем на переднем, а в точке схождения он исчезает совсем. Чем меньше значение перспективы, тем больше эффект глубины и тем больше увеличение объекта на переднем плане. https://uploads.disquscdn.com/images/bccc5d805b020bbdbb395a572d89f91593c7c2a6a2e9c0a059798e72f1ce3190.png

            На рисунке все грани куба имеют одинаковый размер, но как вы можете видеть, задняя грань визуально меньше передней грани.
            https://uploads.disquscdn.com/images/f0ab06d5bd0e3e07868e8f1c056e03c0b7b39ae32d8a05af258dc444af95d744.png

  • Влад Чмель

    Боже бабочка как же это круто
    СПАСИБО ЗА НЕЕ!