翻譯自 《Animated 3D Bar Chart with CSS3》
首先,咱們看一看要實現的效果: css
這篇文章所實現的動畫效果起源於一個小小的想法,這個想法來自於另外一個網站的一篇文章,它介紹瞭如何在網頁中使用CSS、圖片和JavaScript建立立體的柱狀圖。在閱讀了那篇文章以後,我想挑戰一下,嘗試使用純CSS來實現相同的效果。一開始的難點在於建立一個六面半透明的立方體,然後面的難點在於如何建立一個完整的帶有動畫效果的3D柱狀圖。下面,咱們就一塊兒來看一下如何解決這些難點。css3
讓咱們先列舉一些要實現的要求,咱們所實現的柱狀圖應該是:瀏覽器
計劃是任何項目中最重要的一個部分。因此咱們要先制定一個計劃。app
在實際編碼以前,我一般會列出項目中我會遇到的潛在挑戰和解決這些挑戰的方案,而後重複這個過程,直到我獲得一個看起來能夠執行的策略的東西。下面是我爲這個項目提出的挑戰列表和解決方案:佈局
挑戰1 - 帶有可伸縮內核的柱子動畫
咱們知道:網站
因此,咱們須要:ui
總共有五個div。編碼
你可能想知道爲何咱們須要兩個容器?嗯,這是一個很差解釋的問題,但我會嘗試着說明清楚。spa
每一個柱體咱們須要至少一個容器(以保證前三個div的位置),因爲咱們的柱體內核是可伸縮的,因此咱們使用百分比來操縱內核的高度,這就要求容器的高度等於條形圖Y軸的高度。
這看起來很好,可是,有另一個問題,應該有一個選項能夠隱藏移動中的內核,這意味着它應該「低於柱體」而且隱藏。你可能會說有一個解決方法 - overflow: hidden,是的,可是它不適用於這裏的容器,由於它的高度要比實際的柱體高度短,這就是咱們爲何要添加另外一個容器的緣由。
但願我說清楚了,下面咱們繼續。
挑戰2 - 座標軸
座標軸應該:
因此,咱們須要:
實現
如今咱們有了一個整體的計劃,讓咱們把它轉換成代碼。
請注意,文章中的代碼沒有寫瀏覽器前綴。在實際的項目中請不要省略。
挑戰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-wrapper {
overflow: hidden;
}
/* Bar container容器 - 這傢伙是柱形圖裏真正的家長——子元素都是相對於它定位的。 */
.bar-container {
position: relative;
margin-top: 2.5em;
width: 12.5em;
}
/* 右下角的小塊 - 確保內核向下滑動時右下角被「切割」 */
.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-container的寬度設置爲12.5em。這個數字是柱體的正面和右側寬度的總和-在咱們的示例中,它是10+2.5=12.5。
咱們還使用border屬性來建立三角形,並將其放置在 .bar-container的右下角,以確保內核的側邊在垂直移動時能被「切割」。咱們使用:before僞類來生成這個元素。
下面咱們來設置.bar-background:
/* 背面 */
.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-background向上和向右移動2.5em。固然,咱們把左後面和底面傾斜45度。請注意,:after僞元素中將第一個傾斜值設置爲0deg,第二個設置爲-45度,這樣只傾斜元素的Y軸。
接着來設置.bar-foreground:
/* 前面 */
.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-background的樣式同樣,只是方向不一樣。
其中,部分的樣式同時應用在了.bar-foreground和.bar-inner元素上,由於它們的樣子是徹底相同的。
好了,下面咱們繼續設置內核的樣式。
.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);
}複製代碼
好了,柱體的樣式就設置好了,接下來咱們來看座標軸。
挑戰2 - 座標軸
<ul class="graph-container">
<li>
<span>2011</span>
<-- 此處顯示柱狀圖圖的HTML標記 -->
</li>
<li>
<span>2012</span>
<-- 此處顯示柱狀圖圖的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>複製代碼
如您所見,咱們在項目中使用無序列表和span元素來定位X軸和Y軸標籤。
/** 座標軸容器 **/
.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;
}複製代碼
這裏有一個小點,咱們使用線性漸變填充容器背景並將其提高2.5em,爲何?由於座標軸的底端(咱們將在下一個樣式中設置)高度是2.5em。並且座標軸傾斜了45度,因此右下角有一個空白區域。
座標軸的X軸樣式:
/* 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);
}複製代碼
咱們把它傾斜45度,而後向左移動一點,以確保它的位置正確。
座標軸的Y軸樣式:
/* 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);
}複製代碼
這裏沒什麼特別的。同樣將元素傾斜45度,而後向下推一點,以便正肯定位。
座標軸的基本設置就是這些,接下來咱們繼續設置列表項裏面的樣式:
.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);
}複製代碼
這裏有兩個要注意的點。首先,咱們使用浮動將柱體水平排列。一般狀況下都應該很是當心地使用浮動,它會帶來高度塌陷等佈局問題。因此,在這裏你能夠嘗試變爲設置display:inline-block來實現。
第二,咱們在最後一個柱體上添加了一些右邊距。這樣咱們就能夠確保給座標軸底部留出足夠的空間,試着去掉它,你就會明白個人意思。
OK,咱們就快完成了。最後要作的是添加Y軸的文字標記。
/* 文字標記的容器 */
.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軸線條常規樣式 */
.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軸側線 */
.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;
}複製代碼
如您所見,咱們將文字標記容器的寬度設置爲100%,使得背景線可以覆蓋整個座標軸,使用虛線邊框設置Y軸線條的樣式並定位span元素,使文字標籤位於座標軸的外側。使用:before和:after僞元素,能夠減小HTML的代碼量,讓頁面保持乾淨。
到這裏,咱們已經完成了柱狀圖的全部樣式設置,可是咱們缺乏一些重要的變量——大小、顏色和條形填充值!上面說過咱們的圖表是可定製的,因此,我決定不把變量和其餘代碼混合在一塊兒,這樣你就能夠更方便的自定義它們了。
/**************** * 尺寸 * ****************/
/* 圖表的總體大小 */
.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);
}
/* 內核的顏色 */
.bar-inner,
.bar-inner:before { background-color: rgba(5, 62, 123, .6); }
.bar-inner:after { background-color: rgba(47, 83, 122, .7); }
/************************************* * 內核的高度 * *************************************/
.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規範/技術。