—»     —»   Анимированный 3D-график на CSS3
  Раздел: Графики и Диаграммы, CSS/Style Sheets   Комментариев: 1  

Анимированный 3D-график на CSS3



Всё началось с небольшого эксперимента, на который нас вдохновило руководство на ресурсе Nettuts+, в котором рассказывалось о том, как встроить трехмерный график в HTML-страницы при помощи CSS, изображения и кода javascript. После прочтения того руководства, нам стало любопытно, насколько далеко можно зайти в рамках подобного метода. Изначально задумывалось разработать классический полупрозрачный 3D-блок с 6 сторонами. В дальнейшем эксперимент перерос в разработку трехмерного графика, чем мы сегодня и займемся!

Здесь вы можете ознакомиться с тем, над чем мы сегодня будем работать.

Анимированный 3D-график на CSS3

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

Давайте перечислим некоторые ключевые требования. График должен быть:

* независимым от фона
* адаптивным (независимо от количества столбцов)
* масштабируемым (подобно векторной графике)
* легко редактируемым (цвета, размеры, пропорции)

Процесс планирования – одна из важнейших составляющих любого проекта. Так что, давайте составим план.

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

Задача №1 – Столбец с двигающимся внутренним блоком

Что мы знаем:

* Столбец должен быть представлен в виде трехмерного блока, состоящего из 6 сторон
* Внутренний блок должен быть подвижным по вертикальной оси. Также должна присутствовать опция скрывания данного блока.

Что нам требуется:

* 1 div для заднего корпуса, состоящего из 3-х сторон (задняя сторона, дно и левая сторона)
* 1 div для переднего корпуса, состоящего из 3-х сторон (передняя сторона, макушка и правая сторона)
* 1 div для внутреннего блока, состоящего из 3-х сторон наподобие переднего корпуса, но с меньшим значением параметром z-index
* 1 div-контейнер для расположения всех трех частей относительно него и применения единой фоновой текстуры в правом нижнем углу
* 1 div-контейнер с overflow: hidden, чтобы спрятать внутренний блок под столбцом, когда положение доходит до 0 и ниже.

Что в купе дает нам 5 div’ов.

Вы, вероятно, удивляетесь тому, для чего нам 2 контейнера? Ну, это, по-видимому, немного сложно, поэтому мы постараемся объяснить.
Нам нужен как минимум 1 контейнер на столбец (для того чтобы относительно него мы могли расположить передний корпус, задний корпус и внутренний блок). Нам известно, что наш столбец должен быть масштабируемым, и поэтому мы воспользуемся процентным соотношением для управления заполнением столбца, для чего необходимо, чтобы высота нашего контейнера была равна высоте одной из сторон столбца.

Кажется, что все нормально, но погодите, ведь осталась еще кое-какая проблемка – у нас должна быть опция, с помощью которой можно скрывать внутренний блок, что означает, что блок должен опуститься «ниже столбца» и там запрятан. Вы, вероятно, возразите, что для этого есть другое решение: можно использовать overflow: hidden? Да, но не для этого контейнера, так как его высота меньше настоящей высоты столбца. Именно поэтому мы добавляем еще один контейнер поверх него, и уже к нему применяем overflow: hidden.
Надеемся, что в этом есть какой-то смысл. Давайте двигаться дальше.

Задача №2 – Держатель графика

Держатель графика должен быть:

* представлен в трехмерной плоскости с осями и 3-мя сторонами (фон, дно и левая сторона)
* не зависеть от фона
* адаптивным к количеству столбцов и их атрибутам (высота, ширина и т.д.)
* иметь оси X и Y снаружи.

Что нам потребуется:

* 1 неупорядоченный список
* 1 элемент внутри каждого пункта списка для ярлыков на оси X
* 1 столбец внутри каждого пункта
* 1 пункт списка я неупорядоченным списком внутри него для ярлыков на оси Y.

Неупорядоченный список? Разве более семантическим не является использование определения списка для столбикового графика? Ну, возможно это будет более семантически, но мы не можем использовать его, так как нам необходимо обернуть каждый столбик и его собственный ярлык на оси X одним контейнером для того, чтобы иметь возможность расположить их относительно.

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

Реализация

Теперь, когда у нас есть стратегия, давайте преобразуем её в код.

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

Задача №1 – Столбец с двигающимся внутренним блоком

<div class="bar-wrapper">
<div class="bar-container">
<div class="bar-background"></div>
<div class="bar-inner">50</div>
<div class="bar-foreground"></div>
</div>
</div>

Давайте еще раз обсудим назначение каждого элемента:

* bar-wrapper – скрывает .bar-inner, когда тот съезжает ниже столбца
* bar-container – относительно позиционирует .bar-foreground, .bar-inner, .bar-foreground и располагает текстуру фона в левом нижнем углу
* bar-background – создает 3 стороны корпуса: заднюю часть, дно и левую сторону
* bar-inner – вероятно, одна из важнейших частей – внутренний блок
* bar-foreground – создает 3 стороны корпуса: переднюю часть, макушку и правую сторону

Для начала, давайте оформим контейнеры.

/* Bar wrapper - hides the inner bar when it goes below the bar, required */
.bar-wrapper {
overflow: hidden;
}
/* Bar container - this guy is a real parent of a bar's parts - they all are positioned relative to him */
.bar-container {
position: relative;
margin-top: 2.5em; /* should be at least equal to the top offset of background casing */
/* because back casing is positioned higher than actual bar */
width: 12.5em; /* required, we have to define the width of a bar */
}
/* right bottom patch - make sure inner bar's right bottom corner is "cut" when it slides down */
.bar-container:before {
content: "";
position: absolute;
z-index: 3; /* to be above .bar-inner */

bottom: 0;
right: 0;

/* Use bottom border to shape triangle */
width: 0;
height: 0;
border-style: solid;
border-width: 0 0 2.5em 2.5em;
border-color: transparent transparent rgba(183,183,183,1);
}

Заметьте, что мы выставили элементу .bar-container ширину в 12.5em. Это число представляет собой сумму ширин передней и правой сторон столбца. В нашем примере это 10+2.5=12.5.

Мы так же используем границы для создания треугольной формы, расположим ее в правой нижнем углу элемента .bar-container для того, чтобы быть уверенными в том, что внутренняя сторона столбца «обрезается» при вертикальном перемещении. Мы используем псевдо-класс :before для создания этого элемента; в нашем сегодняшнем руководстве мы будем использовать псевдо-классы :before и :after довольно часто.

Теперь давайте оформим задний корпус:

/* Back panel */
.bar-background {
width: 10em;
height: 100%;
position: absolute;
top: -2.5em;
left: 2.5em;
z-index: 1; /* just for reference */
}

.bar-background:before,
.bar-background:after {
content: "";
position: absolute;
}

/* Bottom panel */
.bar-background:before {
bottom: -2.5em;
right: 1.25em;
width: 10em;
height: 2.5em;
transform: skew(-45deg);
}

/* Left back panel */
.bar-background:after {
top: 1.25em;
right: 10em;
width: 2.5em;
height: 100%;

/* skew only the Y-axis */
transform: skew(0deg, -45deg);
}

Как видно, мы перемещаем корпус на 2.5em вверх и вправо. И конечно же, мы наклоняем левую и нижнюю стороны на 45 градусов. Заметьте, что первому наклону мы выставили значение в 0 градусов, а второму в -45 градусов, что позволяет нам наклонить данный элемент вертикально.

Пришло время оформить передний корпус.

/* Front panel */
.bar-foreground {
z-index: 3; /* be above .bar-background and .bar-inner */
}
.bar-foreground,
.bar-inner {
position: absolute;
width: 10em;
height: 100%;
top: 0;
left: 0;
}

.bar-foreground:before,
.bar-foreground:after,
.bar-inner:before,
.bar-inner:after {
content: "";
position: absolute;
}

/* Right front panel */
.bar-foreground:before,
.bar-inner:before {
top: -1.25em;
right: -2.5em;
width: 2.5em;
height: 100%;
background-color: rgba(160, 160, 160, .27);

transform: skew(0deg, -45deg);
}

/* Top front panel */
.bar-foreground:after,
.bar-inner:after {
top: -2.5em;
right: -1.25em;
width: 100%;
height: 2.5em;
background-color: rgba(160, 160, 160, .2);

transform: skew(-45deg);
}

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

Итак, теперь мы займемся оформлением внутреннего блока, которое мы еще не применяли.

.bar-inner {
z-index: 2; /* to be above .bar-background */
top: auto; /* reset position top */
background-color: rgba(5, 62, 123, .6);
height: 0;
bottom: -2.5em;
color: transparent; /* hide text values */

transition: height 1s linear, bottom 1s linear;
}

/* Right panel */
.bar-inner:before {
background-color: rgba(5, 62, 123, .6);
}

/* Top panel */
.bar-inner:after {
background-color: rgba(47, 83, 122, .7);
}

Великолепно! Столбцы настроены. Теперь давайте займемся держателем графика.

Задача №2 – Держатель графика (с осевыми ярлыками)

<ul class="graph-container">
<li>
<span>2011</span>
<-- HTML markup of a bar goes here -->
</li>
<li>
<span>2012</span>
<-- HTML markup of a bar goes here -->
</li>
<li>
<ul class="graph-marker-container">
<li><span>25%</span></li>
<li><span>50%</span></li>
<li><span>75%</span></li>
<li><span>100%</span></li>
</ul>
</li>
</ul>

Как видно, мы используем неупорядоченный список и span-элементы внутри пунктов для того, чтобы расположить ярлыки осей X и Y.

/** Graph Holder container **/
.graph-container {
position: relative; /* required Y axis stuff, Graph Holder's left and bottom sides to be positions properly */
display: inline-block; /* display: table may also work.. */
padding: 0; /* let the bars position themselves */
list-style: none; /* we don't want to see any default <ul> markers */

/* Graph Holder's Background */
background-image: linear-gradient(left , rgba(255, 255, 255, .3) 100%, transparent 100%);
background-repeat: no-repeat;
background-position: 0 -2.5em;
}

Здесь сложность заключается в фоне. Мы используем линейную градацию для заполнения контейнера графика и поднимаем ее на 2.5em. Зачем? Потому что дно нашего держателя графика (оформлением которого мы займемся далее) по высоте составляет 2.5em, и наклонено на 45 градусов, поэтому в правом нижнем углу остается пустое пространство.

Теперь давайте перейдем к стилизации нижней части (дна).

/* Graph Holder bottom side */
.graph-container:before {
position: absolute;
content: "";

bottom: 0;
left: -1.25em; /* skew pushes it left, so we move it a bit in opposite direction */

width: 100%; /* make sure it is as wide as the whole graph */

height: 2.5em;
background-color: rgba(183, 183, 183, 1);

/* Make it look as if in perspective */
transform: skew(-45deg);
}

Мы наклоняем его на 45 градусов и немного смещаем влево для того, чтобы удостовериться в том, что оно расположено правильно. Задаем 50% ширины для того, чтобы быть уверенными в том, что оно заполняет пространство до первого столбца, затем, каждый столбец будет перенимать эти параметры (скоро мы этим займемся).

Теперь давайте перейдем к стилизации левой стороны нашего держателя графика:

/* Graph Holder left side*/
.graph-container:after {
position: absolute;
content: "";

top: 1.25em; /* skew pushes it up so we move it down a bit */
left: 0em;

width: 2.5em;
background-color: rgba(28, 29, 30, .4);

/* Make it look as if in perspective */
transform: skew(0deg, -45deg);
}

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

Теперь мы закончили работу над держателем графика. Давайте добавим немного магии в список пунктов, который удерживает наши столбцы:

/* Bars and X-axis labels holder */
.graph-container > li {
float: left; /* Make sure bars are aligned one next to another*/
position: relative; /* Make sure X-axis labels are positioned relatively to this element */
}
/* A small hack to make Graph Holder's background side be wide enough
...because our bottom side is skewed and pushed to the right, we have to compensate it in the graph holder's background */
.graph-container > li:nth-last-child(2) {
margin-right: 2.5em;
}
/* X-axis labels */
.graph-container > li > span {
position: absolute;
left: 0;
bottom: -2em;
width: 80%; /* play with this one if you change perspective depth */
text-align: center;

font-size: 1.5em;
color: rgba(200, 200, 200, .4);
}

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

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

Итак, мы почти закончили. Последнее, что нам осталось, это добавить маркеры оси Y.

/* Markers container */
.graph-container > li:last-child {
width: 100%;
position: absolute;
left: 0;
bottom: 0;
}

/* Y-axis Markers list */
.graph-marker-container > li {
position: absolute;
left: -2.5em;
bottom: 0;
width: 100%;
margin-bottom: 2.5em;
list-style: none;
}

/* Y-axis lines general styles */
.graph-marker-container > li:before,
.graph-marker-container > li:after {
content: "";
position: absolute;
border-style: none none dotted;
border-color: rgba(100, 100, 100, .15);
border-width: 0 0 .15em;
background: rgba(133, 133, 133, .15);
}

/* Y-axis Side line */
.graph-marker-container > li:before {
width: 3.55em;
height: 0;
bottom: -1.22em;
left: -.55em;
z-index: 2; /* be above .graph-container:after */
transform: rotate(-45deg);
}

/* Y-axis Background line */
.graph-marker-container li:after {
width: 100%;
bottom: 0;
left: 2.5em;
}

/* Y-axis text Label */
.graph-marker-container span {
color: rgba(200, 200, 200, .4);
position: absolute;

top: 1em;
left: -3.5em; /* just to push it away from the graph.. */
width: 3.5em; /* give it absolute value of left offset */

font-size: 1.5em;
}

Как видно, мы выставили 100% ширины нашему держателю маркеров. Это необходимо для того, чтобы прорисовывать черту через весь график, использовать точечную границу для оформления линий нашей оси Y и расположить span-элемент таким образом, чтобы ярлык оси Y был за пределами графика. С помощью :before и :after мы можем сохранить наш HTML-код достаточно ясным.

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

/****************
* SIZES *
****************/
/* Size of the Graph */
.graph-container,
.bar-container {
font-size: 8px;
}
/* Height of Bars */
.bar-container,
.graph-container:after,
.graph-container > li:last-child {
height: 40em;
}

/****************
* SPACING *
****************/
/* spacing between bars */
.graph-container > li .bar-container {
margin-right: 1.5em;
}
/* spacing before first bar */
.graph-container > li:first-child {
margin-left: 1.5em;
}
/* spacing after last bar */
.graph-container > li:nth-last-child(2) .bar-container {
margin-right: 1.5em;
}

/****************
* Colors *
****************/
/* Bar's Back side */
.bar-background {
background-color: rgba(160, 160, 160, .1);
}
/* Bar's Bottom side */
.bar-background:before {
background-color: rgba(160, 160, 160, .2);
}
/* Bar's Left Back side */
.bar-background:after {
background-color: rgba(160, 160, 160, .05);
}
/* Bar's Front side */
.bar-foreground {
background-color: rgba(160, 160, 160, .1);
}
/* Bar's inner block */
.bar-inner,
.bar-inner:before { background-color: rgba(5, 62, 123, .6); }
.bar-inner:after { background-color: rgba(47, 83, 122, .7); }

/*************************************
* Bars Fill *
* Just an example of filling 3 bars *
*************************************/
.graph-container > li:nth-child(1) .bar-inner { height: 25%; bottom: 0; }
.graph-container > li:nth-child(2) .bar-inner { height: 50%; bottom: 0; }
.graph-container > li:nth-child(3) .bar-inner { height: 75%; bottom: 0; }

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

Завершение

Давайте пройдемся по некоторым CSS-спецификациям/техникам, которые мы охватили в данном руководстве. Итак, мы воспользовались:

* transform: skew() и transform: rotate() нужно для трансформации наших элементов таким образом, чтобы вместе они создавали ощущение трехмерного пространства
* псевдо-классы :before и :after нужны для генерации элементов посредством CSS и для сохранения ясности разметки HTML
* псевдо-классы:nth-last-child() и :not нужны для определения конкретных пунктов списка и для того, чтобы избежать добавления дополнительных классов/id в разметку
* linear-gradient вместе с background-position нужны для частичного заполнения элемента фоном
* rgba() для цветов с прозрачностью
* borders для создания фигур типа треугольника

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

Найти проект на Github | Посмотреть демо | Скачать архивом
Внимание! У вас нет прав для просмотра скрытого текста.
Обнаружили ошибку или мёртвую ссылку?
Выделите проблемный фрагмент мышкой и нажмите CTRL+ENTER.
В появившемся окне опишите проблему и отправьте уведомление Администрации ресурса.
Нужна органическая вечная ссылка из данной статьи? Постовой?
Подробности здесь
Вам понравился материал? Поблагодарить легко!
Будем весьма признательны, если поделитесь этой статьей в социальных сетях:

Ключевые тэги: CSS, графики, диаграммы, 3D
Опубликовал Design FactoRy   Прочитано (раз): 9790   |   Оставлено комментариев: 1
Источник материала / оригинал статьи   Распечатать
Другие статьи и новости по теме:
Комментарий #1: 13 июня 2012 @ 19:06
Написал: Overjob — группа: Гости  
На сайте с: --   |   Публикаций: 0   |   Комментариев: 0
ICQ: --- не указано ---
IE как обычно глючит. Когда ослик будет работать, как все нормальные браузеры.
Добавление комментария
Уважаемые пользователи!
При добавлении комментариев на сайт Вам следует учитывать следующее - все комментарии проверяются Администрацией на предмет отсутствия спама. При обнаружении признаков спама, в оставленном Вами комментарии, сам комментарий будет незамедлительно удалён, а Ваш IP-адрес будет забанен без предупреждения! Учётные записи пользователей, рассылающих спам, блокируются/удаляются без права последующего восстановления.

С уважением, Администрация сайта.
* = поля обязательны к заполнению
Полужирный Наклонный текст Подчеркнутый текст Зачеркнутый текст | Выравнивание по левому краю По центру Выравнивание по правому краю | Вставка смайликов Выбор цвета | Скрытый текст Вставка цитаты Преобразовать выбранный текст из транслитерации в кириллицу Вставка спойлера
Вопрос : Назовите месяц October по-русски
Подтверждение кода безопасности :

Включите эту картинку для отображения кода безопасности
обновить, если не виден код


Фотограф новорожденных Москва
Свадебные видеооператоры и фотографы. Руслан Мигранов - художник и фотограф
katexristuk.ru
Торт холодное сердце
Свадебные, праздничные, корпоративные и детские торты
votetotort.ru
Металлочерепица цена
Описания, цены, места продаж. Инструкции по монтажу металлочерепицы
премиумкровля.рф
Популярные публикации


















Свежие шаблоны сайтов каждый день
С миру по нитке
«    Декабрь 2017    »
ПнВтСрЧтПтСбВс
 123
45678910
11121314151617
18192021222324
25262728293031