<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

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

          共 8438字,需瀏覽 17分鐘

           ·

          2020-10-23 15:04

          來源 | https://juejin.im/post/6844903857147871239

          首先,我們看一看要實現(xiàn)的效果:

          今天這篇文章所實現(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)核的柱子

          50
          讓我們再次回顧每個元素的用途:
          • 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è))

          首先,讓我們設(shè)置容器的樣式。
          /* 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-container的寬度設(shè)置為12.5em。這個數(shù)字是柱體的正面和右側(cè)寬度的總和-在我們的示例中,它是10+2.5=12.5。
          我們還使用border屬性來創(chuàng)建三角形,并將其放置在 .bar-container的右下角,以確保內(nèi)核的側(cè)邊在垂直移動時能被“切割”。我們使用:before偽類來生成這個元素。
          下面我們來設(shè)置.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。當(dāng)然,我們把左后面和底面傾斜45度。請注意,:after偽元素中將第一個傾斜值設(shè)置為0deg,第二個設(shè)置為-45度,這樣只傾斜元素的Y軸。
          接著來設(shè)置.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的樣式一樣,只是方向不同。
          其中,部分的樣式同時應(yīng)用在了.bar-foreground和.bar-inner元素上,因為它們的樣子是完全相同的。
          好了,下面我們繼續(xù)設(shè)置內(nèi)核的樣式。
          .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);}
          好了,柱體的樣式就設(shè)置好了,接下來我們來看坐標軸。
          挑戰(zhàn)2 - 坐標軸
          <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>
          如您所見,我們在項目中使用無序列表和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,為什么?因為坐標軸的底端(我們將在下一個樣式中設(shè)置)高度是2.5em。而且坐標軸傾斜了45度,所以右下角有一個空白區(qū)域。
          坐標軸的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度,然后向下推一點,以便正確定位。
          坐標軸的基本設(shè)置就是這些,接下來我們繼續(xù)設(shè)置列表項里面的樣式:
          .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);}
          這里有兩個要注意的點。首先,我們使用浮動將柱體水平排列。通常情況下都應(yīng)該非常小心地使用浮動,它會帶來高度塌陷等布局問題。所以,在這里你可以嘗試變?yōu)樵O(shè)置display:inline-block來實現(xiàn)。
          第二,我們在最后一個柱體上添加了一些右邊距。這樣我們就可以確保給坐標軸底部留出足夠的空間,試著去掉它,你就會明白我的意思。
          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軸線條常規(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;}
          如你所見,我們將文字標記容器的寬度設(shè)置為100%,使得背景線能夠覆蓋整個坐標軸,使用虛線邊框設(shè)置Y軸線條的樣式并定位span元素,使文字標簽位于坐標軸的外側(cè)。使用:before和:after偽元素,可以減少HTML的代碼量,讓頁面保持干凈。
          到這里,我們已經(jīng)完成了柱狀圖的所有樣式設(shè)置,但是我們?nèi)鄙僖恍┲匾淖兞俊笮 ㈩伾蜅l形填充值!上面說過我們的圖表是可定制的,所以,我決定不把變量和其他代碼混合在一起,這樣你就可以更方便的自定義它們了。
          /**************** * 尺寸        * ****************/ /* 圖表的整體大小 */.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;?}
          在下載的源碼中,您將無法找到這一部分代碼,因為我在那里做了一些更有趣的事情——我使用了單選按鈕讓您在不修改代碼的情況下使用變量。但是,如果您只需要定制一個靜態(tài)圖形,那么就從上面獲取代碼片段,并根據(jù)您的喜好對其進行定制。
          總結(jié)
          讓我們回顧一下文章中介紹的一些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)建三角形形狀

          感謝閱讀。

          瀏覽 20
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲激情久久久久豆花 | 亚洲黄片免费观看 | 大香蕉久久久久久成人草 | 特级无码一区二区三区 | 无码毛片一区二区三区四区五区六区 |