- PVSM.RU - https://www.pvsm.ru -
Все началось с небольшого эксперимента из учебника +Nettuts, который рассказывает, как встроить 3D-граффики в HTML-страницы с помощью CSS, изображений и JavaScript. После прочтения урока я загорелся желанием превратить эту идею на чистом CSS и посмотреть, как далеко я могу её усовершенствовать. Первоначальная задача заключалась в создании классических полупрозрачных 3D блоков, с 6 сторонами. Наша задача состоит в том, чтобы создать 3D-график.
ДЕМО [1]
Исходные файлы [2]
Запишем некоторые ключевые требования, которые должны быть в грффике.
Этап планирования является наиболее важной частью любого проекта.
Перед тем как начать кодировать, я обычно записываю все потенциальные проблемы. Вот список задач с решениями, которые я придумал для этого проекта:
Что мы знаем:
Что нам понадобиться:
Вы можете удивиться, зачем нам нужно два блока? Нам нужно по крайней мере один контейнер в графике. Мы знаем, что график должен быть масштабируемый, поэтому мы используем проценты, этим мы будем манипулировать значениями графика, наша высота блоков должна быть равна высоте одной из сторон графика.
Так же есть и другая проблема — должна быть возможность скрыть внутренний блок в движении, а значит, должны находится «под панелью» и скрывать их там. Вы можете подумать что решение для этого — overflow: hidden, не так ли? Да, но не для этого блока, его высота меньше, чем фактическая высота графика. Именно поэтому мы добавим еще один блок над нем и применим нему overflow: hidden.
Фиксатор должен:
Хм, неупорядоченный список? Разве не более эффективно использовать список определений для графика? Конечно, это более эффективно, но мы не можем использовать его, потому что для каждого блока нам надо добавить собственные метки по оси X.
Хорошо, но почему не использовать элемент списка, а использовать второй контейнер блока? Мы не можем сделать это, потому что мы должны поставить метки по оси Х вне графика и так как верхняя часть блока скрывает данные которые переполняют его, мы будем использовать элементы списка, чтобы убедиться, что все элементы расположены правильно.
Теперь у нас есть план, давайте преобразуем его в код.
<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 - 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's на 12.5em. Это число является суммой значения ширины передней стороны и правой стороны — в нашем примере это 10 + 2,5 = 12,5
Мы также используем border, чтобы сформировать треугольник и поместить его в правом нижнем углу .bar-container, чтобы убедиться, что стороны внутреннего блока будут уменьшаться, когда он перемещается по вертикали. Мы используем псевдо-класс для создания этого элемента.
Стиль задней части блока:
/* 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 градусов. Обратите внимание, что мы устанавливаем первое значение наклона 0deg, а второе до 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);
}
<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>
Как видите, мы используем неупорядоченный список и диапазон внутри элементов для размещения 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-оси линий и положение диапазона элементов таким образом, что метки 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, которые мы рассмотрели в этой статье.
ДЕМО [1]
Исходные файлы [2]
Автор: Lecaw
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/veb-dizajn/8047
Ссылки в тексте:
[1] ДЕМО: http://tympanus.net/Tutorials/Animated3DBarChart/
[2] Исходные файлы: http://lecaw.ru/index.php/component/k2/item/369-jbiconicstaranimirovannyj-3d-grafik-na-css3jbiconicstar
Нажмите здесь для печати.