純CSS3實現(xiàn)柱狀圖的3D立體動畫效果


今天這篇文章所實現(xiàn)的動畫效果起源于一個小小的想法,這個想法來自于另一個網(wǎng)站的一篇文章,它介紹了如何在網(wǎng)頁中使用CSS、圖片和JavaScript創(chuàng)建立體的柱狀圖。在閱讀了那篇文章之后,我想挑戰(zhàn)一下,嘗試使用純CSS來實現(xiàn)相同的效果。一開始的難點在于創(chuàng)建一個六面半透明的立方體,而后面的難點在于如何創(chuàng)建一個完整的帶有動畫效果的3D柱狀圖。
下面,我們就一起來看一下如何解決這些難點。
讓我們先列舉一些要實現(xiàn)的要求,我們所實現(xiàn)的柱狀圖應(yīng)該是:
背景獨立(即柱狀圖與背景互不影響)
自適應(yīng)的(柱子數(shù)量的多少不會影響布局)
可縮放(如矢量圖一樣)
易于定制(顏色、尺寸和比例)
計劃是任何項目中最重要的一個部分。所以我們要先制定一個計劃。
在實際編碼之前,我通常會列出項目中我會遇到的潛在挑戰(zhàn)和解決這些挑戰(zhàn)的方案,然后重復(fù)這個過程,直到我得到一個看起來可以執(zhí)行的策略的東西。下面是我為這個項目提出的挑戰(zhàn)列表和解決方案:
挑戰(zhàn)1 - 帶有可伸縮內(nèi)核的柱子
我們知道:
一個柱狀圖是由6個面組成的立體圖形
這個柱狀圖的內(nèi)核是可以垂直伸縮的,并且有一個選項可以隱藏它
所以,我們需要:
一個div,生成柱狀圖的三個面(背部、底部、左側(cè))
一個div,生成柱狀圖的另三個面(正面、頂部、右側(cè))
一個div,生成內(nèi)核柱體的三個面,與上面的第二個div類似,但是它的z-index值要小
一個div,作為容器,用于定位以上的三個組件,并且在右下角實現(xiàn)一個實色的背景
一個div,帶有overflow: hidden的容器,用于內(nèi)核柱體的高度為0時,隱藏它。
總共有五個div。
你可能想知道為什么我們需要兩個容器?嗯,這是一個不好解釋的問題,但我會嘗試著說明清楚。
每個柱體我們需要至少一個容器(以保證前三個div的位置),由于我們的柱體內(nèi)核是可伸縮的,所以我們使用百分比來操縱內(nèi)核的高度,這就要求容器的高度等于條形圖Y軸的高度。
這看起來很好,但是,有另外一個問題,應(yīng)該有一個選項可以隱藏移動中的內(nèi)核,這意味著它應(yīng)該“低于柱體”并且隱藏。你可能會說有一個解決方法 - overflow: hidden,是的,但是它不適用于這里的容器,因為它的高度要比實際的柱體高度短,這就是我們?yōu)槭裁匆砑恿硪粋€容器的原因。
希望我說清楚了,下面我們繼續(xù)。
挑戰(zhàn)2 - 坐標軸
坐標軸應(yīng)該:
是一個三維立體坐標軸,它包含3個面(背景面,X軸面,Y軸面)
背景獨立
自適應(yīng)柱體的數(shù)量和屬性(width,height等)
外側(cè)有X軸與Y軸的文字標簽
所以,我們需要:
一個無序列表
X軸標簽的每個列表項內(nèi)有一個span元素
每個列表項中有一個柱體
Y軸標簽內(nèi)包含一個無序列表
實現(xiàn)
現(xiàn)在我們有了一個總體的計劃,讓我們把它轉(zhuǎn)換成代碼。
請注意,文章中的代碼沒有寫瀏覽器前綴。在實際的項目中請不要省略。
挑戰(zhàn)1 - 帶有可伸縮內(nèi)核的柱子
bar-wrapper – 當(dāng).bar-inner滑動到柱體的下方時隱藏它
bar-container – 作為.bar-foreground, .bar-inner, .bar-foreground定位的參考元素,并設(shè)置底角的背景顏色
bar-background – 生成柱狀圖的三個面(背部、底部、左側(cè))
bar-inner – 最重要的部分 – 柱子內(nèi)核
bar-foreground – 生成柱狀圖的另三個面(正面、頂部、右側(cè))
/* Bar wrapper容器 - 當(dāng)內(nèi)核低于柱體高度時隱藏內(nèi)核,必需的 */.bar-wrapper {overflow: hidden;}/* Bar container容器 - 這家伙是柱形圖里真正的家長——子元素都是相對于它定位的。*/.bar-container {position: relative;margin-top: 2.5em;width: 12.5em;}/* 右下角的小塊 - 確保內(nèi)核向下滑動時右下角被“切割” */.bar-container:before {content: "";position: absolute;z-index: 3;bottom: 0;right: 0;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-background {width: 10em;height: 100%;position: absolute;top: -2.5em;left: 2.5em;z-index: 1;}.bar-background:before,.bar-background:after {content: "";position: absolute;}/* 底面 */.bar-background:before {bottom: -2.5em;right: 1.25em;width: 10em;height: 2.5em;transform: skew(-45deg);}/* 左后面 */.bar-background:after {top: 1.25em;right: 10em;width: 2.5em;height: 100%;/* 僅傾斜Y軸 */transform: skew(0deg, -45deg);}
/* 前面 */.bar-foreground {z-index: 3; /* 在 .bar-background 和.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;}/* 右前面 */.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);}/* 前面 */.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; /* 在.bar-background的上面 */top: auto; /* 重置 top屬性 */background-color: rgba(5, 62, 123, .6);height: 0;bottom: -2.5em;color: transparent; /* 隱藏文字 */transition: height 1s linear, bottom 1s linear;}/* 右面 */.bar-inner:before {background-color: rgba(5, 62, 123, .6);}/* 上面 */.bar-inner:after {background-color: rgba(47, 83, 122, .7);}
<ul class="graph-container"><li><span>2011span><-- 此處顯示柱狀圖圖的HTML標記 -->li><li><span>2012span><-- 此處顯示柱狀圖圖的HTML標記 -->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>
/** 坐標軸容器 **/.graph-container {position: relative;display: inline-block;padding: 0;list-style: none; /* 去除列表元素自帶的小黑點 *//* 背景 */background-image: linear-gradient(left , rgba(255, 255, 255, .3) 100%, transparent 100%);background-repeat: no-repeat;background-position: 0 -2.5em;}
/* X軸 */.graph-container:before {position: absolute;content: "";bottom: 0;left: -1.25em; /* 傾斜會將它向左推,所以我們將它向相反的方向移動一點。*/width: 100%; /* 確保它和整個組件一樣寬 */height: 2.5em;background-color: rgba(183, 183, 183, 1);transform: skew(-45deg);}
/* Y軸 */.graph-container:after {position: absolute;content: "";top: 1.25em; /* 傾斜會將其向上推,因此我們將其向下移動一點。*/left: 0em;width: 2.5em;background-color: rgba(28, 29, 30, .4);transform: skew(0deg, -45deg);}
.graph-container > li {float: left; /* 水平排列 */position: relative;}.graph-container > li:nth-last-child(2) {margin-right: 2.5em;}/* X軸的文字標簽 */.graph-container > li > span {position: absolute;left: 0;bottom: -2em;width: 80%;text-align: center;font-size: 1.5em;color: rgba(200, 200, 200, .4);}
/* 文字標記的容器 */.graph-container > li:last-child {width: 100%;position: absolute;left: 0;bottom: 0;}/* Y軸文字標記列表 */.graph-marker-container > li {position: absolute;left: -2.5em;bottom: 0;width: 100%;margin-bottom: 2.5em;list-style: none;}/* Y軸線條常規(guī)樣式 */.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軸側(cè)線 */.graph-marker-container > li:before {width: 3.55em;height: 0;bottom: -1.22em;left: -.55em;z-index: 2;transform: rotate(-45deg);}/* Y軸背景線 */.graph-marker-container li:after {width: 100%;bottom: 0;left: 2.5em;}/* Y軸文本標簽 */.graph-marker-container span {color: rgba(200, 200, 200, .4);position: absolute;top: 1em;left: -3.5em;width: 3.5em;font-size: 1.5em;}
/***************** 尺寸 *****************//* 圖表的整體大小 */.graph-container,.bar-container {font-size: 8px;}/* 柱體的高度 */.bar-container,.graph-container:after,.graph-container > li:last-child {height: 40em;}/***************** 間距 *****************//* 柱體的間距 */.graph-container > li .bar-container {margin-right: 1.5em;}/* 第一個柱體的左邊距 */.graph-container > li:first-child {margin-left: 1.5em;}/* 最后一個柱體的右邊距 */.graph-container > li:nth-last-child(2) .bar-container {margin-right: 1.5em;}/***************** 顏色 *****************//* 柱體的背面顏色 */.bar-background {background-color: rgba(160, 160, 160, .1);}/* 柱體的底面顏色 */.bar-background:before {background-color: rgba(160, 160, 160, .2);}/* 柱體的左后面顏色 */.bar-background:after {background-color: rgba(160, 160, 160, .05);}/* 柱體的正面顏色 */.bar-foreground {background-color: rgba(160, 160, 160, .1);}/* 內(nèi)核的顏色 */.bar-inner,.bar-inner:before { background-color: rgba(5, 62, 123, .6); }.bar-inner:after { background-color: rgba(47, 83, 122, .7); }/************************************** 內(nèi)核的高度 **************************************/.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規(guī)范/技術(shù)。
transform:skew()和transform:rotate()用于傾斜和旋轉(zhuǎn)元素,它們組合起來使元素模擬產(chǎn)生三維立體的效果。
:before和:after偽元素可以保持HTML標記相對干凈
:nth-last-child()和:not是針對特定列表項的偽類,可以避免向HTML中添加額外的類/id。
linear-gradient和background-position一起使用可以實現(xiàn)背景的部分填充
rgba()可以實現(xiàn)具有透明度的顏色
border屬性可以創(chuàng)建三角形形狀

