Как создать впечатляющую 3D графику в CSS3

Эта статья показывает, как использовать преобразования для создания и анимирования 3D объектов, используя только CSS.

CSS 3D преобразования быстро становятся признанным способом добавления глубины и интерактивности в веб-проекты.

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

Также мы изучим несколько продвинутых возможностей CSS3 и рассмотрим некоторые общие вопросы.

Зачем использовать CSS?

Есть огромное количество способов создать 3D графику в HTML. На основе JS, Canvas, SVG, доступны даже решения на основе WebGL, и все они имеют свои достоинства, но есть еще и CSS.

Решение на базе CSS обходится без изображений и способно использовать графический процессор для ускорения обработки графики.

При этом не требуются плагины, и CSS может жить вне стен canvas на вашей странице:

на базе CSS

Установка свойства perspective может произвести впечатляющий эффект

CSS 3D графика не так оптимизирована как WebGL. Отдельной темой является несовместимые браузеры. Тем не менее, включение 3D объектов в веб-проекты открывает новые направления работы, и может быть использовано уже сегодня.

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

Не забудьте включить префиксы для Mozilla, Opera, MS, а также версии без префиксов в случае необходимости. Полные версии кода CSS (с префиксами) находятся в файлах проекта.

Основы: создание 3D куба

Для начала мы построим базовый 3D куб, разместив и анимировав его в 3D пространстве. Сначала напишем код HTML, который будет представлять части 3D куба:

<div class="stage">
  <div class="cube">
    <figure class="back"></figure>
    <figure class="top"></figure>
    <figure class="bottom"></figure>
    <figure class="left"></figure>
    <figure class="right"></figure>
    <figure class="front"></figure>
  </div>
</div>

Я задействовал элемент figure, но можно было использовать div, span или любой другой тип элемента на ваше усмотрение.

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

две главные части

Слева – элемент div без применения преобразования. Справа – фигура повернута в 3D пространстве

Подготовка сцены

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

Задаем глубину сцены с помощью CSS свойства perspective:

.stage {
  width: 300px; height: 300px;
  -webkit-perspective: 1600px;
  -webkit-perspective-origin: 50% -240px;
}

Задание большей величины для свойства perspective создает менее заметный 3D эффект, меньшей – делает его более выраженным.

Значение в 800 пикселей или около того подходит, как правило, для большинства маленьких объектов, но если вы создаете что-то большее (например, небоскреб) вы можете использовать меньшее значение для создания более выраженных углов.

При задании свойства perspective необходимо также установить perspective-origin (свойство, определяющее положение виртуальной камеры, обращенной на сцену), позиционируемое на осях X и Y.

Создание форм: пространственное мышление

Создание 3D форм при помощи HTML и CSS включает в себя представление объекта в виде набора двухмерных плоскостей.

Вместо того чтобы рисовать вершины и собирать формы из точек и линий, что делается, как вам известно, в других 3D программах, мы будем работать с двухмерными плоскостями, позиционируя их одновременно. Мы собираем куб из шести плоскостей, соответствующих боковым сторонам, вершине и основанию.

Для начала придадим элементам figure форму и стиль:

figure {
  display: block; position: absolute;
  width: 300px; height: 300px;
  background-color: #60c2ef;
}

На следующем шаге нужно указать, где они должны располагаться в 3D пространстве.

Время преобразований

Размещаем фигуры при помощи свойства transform. Преобразования в CSS состоят из последовательности инструкций, указывающих форме, как перемещаться, поворачиваться, наклоняться и изменяться в масштабе. Инструкции читают слева направо.

Например:

-webkit-transform: rotateY(45deg) translateZ(-100px) rotateX(10deg) 
Мы можем поместить каждую сторону куба на место, начиная с передней и задней грани: 
.cube { -webkit-transform-style: preserve-3d; }
figure { -webkit-transform-origin: 50% 50% 0; }
.front { -webkit-transform: translateZ(150px); }
.back { -webkit-transform: rotateY(180deg) translateZ(150px); }

Обратите внимание на использование свойства transform-style: когда оно установлено в значении preserve-3d, преобразования над сторонами куба будут осуществляться в их собственном 3D пространстве.

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

Свойство transform-origin задает точку в X, Y, Z координатах, которая выполняет роль центра вращения (это середина передней части элемента):

Свойство transform-origin

Плоские элементы HTML в 3D пространстве

Передняя фигура смещена на 150 пикселей вперед, задняя – перевернута на 180 градусов и сдвинута на 150 пикселей к задней части сцены.

Порядок здесь имеет значение – правила преобразования применяются слева направо. Для второго преобразования задано положительное значение: после поворота передняя сторона обращена к задней части сцены.

Как и ранее порядок правил преобразований имеет значение. Если элемент повернут, его Z-ось будет находиться под другим углом, что повлияет на любое другое преобразование.

Теперь разместим другие стороны:

.top { -webkit-transform: rotateX(90deg) translateZ(150px); }
.bottom { -webkit-transform: rotateX(-90deg) translateZ(150px); }
.left { -webkit-transform: rotateY(-90deg) translateZ(150px); }
.right { -webkit-transform: rotateY(90deg) translateZ(150px); }

Теперь у нас полностью есть куб, расположенный на 3D сцене.

Двигай, двигай

Давайте повернем наше 3D творение на сцене с помощью CSS анимаций:

@-webkit-keyframes rotate {
  0% { -webkit-transform: rotateY(0); }
  100% { -webkit-transform: rotateY(360deg); }
}

CSS анимации создаются с помощью последовательности ключевых кадров. Ключевые кадры – это набор состояний объекта, установленных с использованием процентных отношений.

Анимация начинается с нулевого поворота и завершается полным поворотом элемента вокруг оси Y.

Примените это набор ключевых кадров со свойством animation:

.cube { -webkit-animation: rotate 10s infinite linear; }

Анимация поворота, примененная здесь, рассчитана на 10 секунд, повторяется бесконечно с постоянной линейной скоростью:

Анимация поворота

Готовый куб, созданный из шести HTML элементов

Затенение

У нас есть куб, вращающийся на сцене, но сейчас он освещен со всех сторон. Чтобы добавить тень, не задействовав больше селекторов, мы воспользуемся псевдо-селекторами.

Псевдо-селекторы – это что-то вроде дополнительных HTML элементов, которые можно вставить до и после содержимого элемента.

Они предоставляют нам дополнительные возможности и могут содержать градиенты, цвета или даже текст. Таким образом, мы можем анимировать затемнение на каждой стороне куба.

Нам нужно два градиента: один – для случая, когда поверхность поворачивается налево, другой – для поворота направо:

figure:before, figure:after {
  content: ""; display: block; position: absolute;
  width: 100%; height: 100%; opacity: 0;
}
figure:before {
  background: -webkit-radial-gradient(top left, rgba(0, 0, 0, 0.5), #000000);
}
figure:after {
  background: -webkit-radial-gradient(top right, rgba(0, 0, 0, 0.5), #000000);
}

Элементы before и after в этом примере являются псевдо-селекторами, которые могут быть стилизованы и анимированы.

Важно отметить, что эта функция еще не в полной мере поддерживается браузерами – Google Chrome, Firefox и IE10 предлагают различные уровни поддержки – и, возможно, ситуация улучшится.

Применяем анимацию к каждому псевдо-селектору для определения времени отображения/скрытия этих градиентов:

.front:before { -webkit-animation: frontShading1 10s infinite linear; }
...

Каждая анимация состоит из набора ключевых кадров, которые отображают или скрывают градиент во время анимации.

Ниже приведены ключевые кадры, примененные к задней стороне:

@-webkit-keyframes frontShading1 {
  2% { opacity: 0; }
  25% { opacity: 0.8; }
  35% { opacity: 0.8; }
  50% { opacity: 0; }
}
...

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

Вершина и основание

Следующий шаг – вершина и основание куба. Для вершины нужен градиент, который выглядит так, как будто ничего не движется.

Добавьте градиент к элементу top и поверните его в противоположном направлении:

.top:after {
  opacity: 0.5; width: 200%; height: 200%;
  margin-left: -50%; margin-top: -50%;
  background: -webkit-radial-gradient(bottom, rgba(0, 0, 0, 0), #000000);
-webkit-animation: rotateTop 10s infinite linear;
}
@-webkit-keyframes rotateTop {
  0% { -webkit-transform: rotateZ(0); }
  100% { -webkit-transform: rotateZ(360deg); }
}

Основание куба не будет видно, но мы можем использовать его, чтобы добавить атрибут box-shadow:

.bottom {
  -webkit-box-shadow: 0 10px 100px rgba(0, 0, 0, 0.7);
  background-color: rgba(0, 0, 0, 0);
}
box-shadow

Затенение добавляет чувство глубины в противоположность плоской сцене

Больше, чем просто цвет

К этому моменту мы, используя только CSS, создали затененный анимированный куб, правда, с однотонными сторонами. Поскольку мы работаем с HTML элементами, мы можем поиграть с содержимым.

Грани куба могут содержать изображения, текст или даже другие анимации. В примере, приведенном ниже, я применил несколько фоновых изображений из игры Minecraft:

figure {
  background-image: url(../images/mc_side.png);
  background-size: 100%;
}
.top {
  background-image: url(../images/mc_top.png);
}

Затенение, которое мы добавили раннее, все еще присутствует здесь, придавая сторонам куба более сильное ощущение глубины. Этот эффект будет работать для любого контента элемента figure.

Отражения

Если анимированного затенения и тени недостаточно, мы можем добавить сцене немного больше глянца с помощью причудливых WebKit фильтров (учтите, что в настоящий момент эта функция возможна только с WebKit):

figure {
  -webkit-box-reflect: below 0 -webkit-gradient(linear, left top, left bottom, from(transparent), color-stop(50%, transparent), to(RGBA(0, 0, 0, 0.1)));
}

Куб с твитами

Давайте создадим что-то более практичное. В этом примере мы сделаем куб местом отображения ваших самых последних твитов и поместим некоторую вторичную информацию на сторону куба с возможностью следовать за вами в Twitter.

Настройка HTML

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

Используем следующие две текстуры с кубом:

figure {
  background-color: #eeeeee;
  background: url(../images/white-noise.jpg);
}
.front {
  background: #e0e0e0 url(../images/net-logo.jpg) no-repeat;

Добавляем содержимое

Добавим содержимое, которое попадает в поле зрения пользователя при повороте куба. Это будет происходить на правой стороне куба. Подключаем в работу немного JavaScript для вызова кнопки «Follow» (доступна на странице кнопок Twitter).

Элемент figure с классом right должен содержать что-то вроде этого:

<figure class="right">
  <p>The world's best selling magazine for web designers and developers since 1994</p>
  <a href="https://twitter.com/netmag" class="twitter-follow-button" datashow-count="false">Follow @netmag</a>
  <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s)[0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+'://platform.twitter.com/widgets.js';fjs.parentNode.insertBefore(js,fjs);}}(document, 'script', 'twitter-wjs');</script>
</figure>

Кнопка «Follow» размещается путем добавления правила iframe в CSS:

.right iframe { padding-left: 90px; margin-top: -30px; }
правила iframe в CSS

Добавление фоновых изображений к HTML элементам придает сцене более презентабельный вид

Размещаем твит на кубе

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

Выберите «Создать новую кнопку» (Create new button), затем введите нужный логин Twitter в поле «Имя пользователя» (Username). В этом примере мы используем логин netmag.

Нажмите «Создать кнопку» (Create widget button), чтобы сгенерировать встраиваемый код.

Мы можем стилизовать виджет и задать ширину, высоту и некоторые данные-значения в коде. Замените YOUR_WIDGET_ID на идентификатор, предоставленный в вашем коде для вставки:

<figure class="front">
  <p style="padding: 0; margin: 85px 25px 0 25px; width: 250px">
  <a class="twitter-timeline" href="https://twitter.com/netmag" width="250" height="200" data-chrome="noheader noborders nofooter transparent" data-tweet-limit="1" data-widget-id="YOUR_WIDGET_ID"></a>
  <script>!function(d,s,id){var js,fjs=d.getElementsByTagName(s) [0],p=/^http:/.test(d.location)?'http':'https';if(!d.getElementById(id)){js=d.createElement(s);js.id=id;js.src=p+"://platform.twitter.com/widgets.js";fjs.parentNode.insertBefore(js,fjs);}}(document,"script","twitter-wjs");</script>
  </p>
</figure>

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

Для затенения нам не потребуется анимация с помощью ключевых кадров: оно будет проявляться при наведении или возникновении некоторого события.

Добавим несколько переходов к затенению псевдо-селекторов:

.right:before { opacity: 0.4; -webkit-transition: all 0.4s ease; }
.right:after { display: none; }
.front:before { opacity: 0.1; -webkit-transition: all 0.4s ease; }
.front:after { display: none; }

Для псевдо-селектора на правой грани установлено значение непрозрачности 0,4. Это добавляет небольшую тень, и можно анимировать непрозрачность так, чтобы грань становилась светлее при повороте к лицевой стороне.

Псевдо-селектор right:after скрыт, так как мы не будем поворачивать куб на столько, чтобы он потребовался. Лицевой стороне придано затемнение, тем не менее, она светлее правой стороны, когда та поворачивается вперед:

Псевдо-селектор right:after

Поворот 3D куба вокруг оси Y

Анимация при наведении

Теперь, добавив эффекты затенения, мы создадим анимированный эффект «подглядывания» когда пользователь наводит курсор на куб при помощи CSS состояния hover:

.cube:hover {
  -webkit-transform: rotateY(-50deg);
  -webkit-transition: all 0.4s ease;
}
.cube:hover figure.right:before, .cube:hover figure.front:before {
  opacity: 0.2;
  -webkit-transition: all 0.4s ease;
}

При наведении курсора куб поворачивается на 50 градусов влево. Это преобразование производится в виде плавного перехода путем применения свойства transition.

Одновременно с этим, непрозрачность псевдо-селекторов на передней и правой сторонах куба переходит в значение 0.2.

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

Полный код HTML и CSS можно найти в файлах проекта:

Полный код HTML

Трехмерный «твит-куб», показывающий дополнительную информацию при наведении курсора

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

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

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

Производительность и тестирование

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

Проводите тестирование на разных платформах: посетители могут также использовать мобильные устройства или устаревшие, медленные компьютеры.

И хотя это только вопрос времени, когда все браузеры будут поддерживать 3D преобразования, градиенты и все изящные штрихи, которые мы использовали здесь, реальность такова, что большинство браузеров все еще их не поддерживают.

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

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

В данном случае мы воспользуемся скриптом Modernizr для того, чтобы выяснить поддерживаются ли 3D преобразования, и если нет, отобразим статичное изображение.

Для начала подключите Modernizr в заголовке HTML:

<script src="js/modernizr.js"></script>

При загрузке в тег <head> будет вставлен класс csstransforms3d. Затем мы воспользуемся этой информацией для отображения или скрытия резервного варианта:

.stage { display: none; }
.csstransforms3d .stage { display: block; }
.fallback-stage {
  width: 100%; height: 600px;
  background: url(../images/fallback.png);
}
.csstransforms3d .fallback-stage { display: none; }

В этом примере альтернативой служит статичное изображение. Используйте запасной элемент div, чтобы представить двухмерный контент в браузере или альтернативное сообщение:

элемент div

Текстуры, примененные к сторонам 3D куба с твитами

Следующие шаги

Стилизованный 3D куб – это, вероятно, не первое, что большинство заказчиков веб-дизайна просят сделать, но некоторые из приведенных подходов могут иметь другое применение.

Можно создать эффект 3D перехода при наведении на логотип – броский способ продемонстрировать новый продукт – или использовать данные подходы для представления и навигации в комплексных данных. Использование Z оси в дизайне открывает двери для многих интересных и веселых идей.

Перевод статьи «How to create impressive 3D graphics in CSS3» был подготовлен дружной командой проекта Сайтостроение от А до Я.