CSS動畫之旋轉魔方輪播

好久沒有回頭來複習CSS方面的知識了, 正好又到了月底寫文章的deadline......
因此此次選擇了詳細鞏固一下CSS3動畫有關的知識點,由於以前只是用過一些屬性並無深究細節。css

在我本身寫完這篇文章的時候, 才以爲CSS確實可以實現不少炫酷的效果。html

本篇文章demo的完成本身也是查了不少相關知識點和借鑑了一些文章中的內容。但無論怎樣, 做爲一個前端菜鳥, 老是在不斷學習中成長的。這句話寫在這裏本身內心也安心一些。(逃......前端

最終的demo效果地址

下面我將一步一步詳解如何利用純CSS實現一個旋轉魔方輪播的效果。css3

總的來講咱們須要實現如下兩個主要功能:瀏覽器

  • 構建一個可以旋轉的立方體

  • 讓立方體擁有基本輪播所具備的特性

但在完成以上兩點以前咱們須要再次瞭解或熟悉一下實現其功能的CSS3基礎知識點:wordpress

  1. transition

  2. transform

  3. perspective

  4. preserve-3d

  5. animation

transition屬性 --- 過渡效果

transition: property duration timing-fucntion delay;

這個屬性應該都很熟悉, 也不過多講, 只是列出其所具備的全部子屬性。函數

過渡屬性 --- 過渡持續時間 --- 過渡函數(曲線) --- 過渡延遲工具

transition-timing-function: linear|ease|ease-in|ease-out|ease-in-out; 原生具備的基本過渡函數

transform屬性 --- 對元素進行2D或3D轉換

它有幾個經常使用的變換方法:scale scale3d translate translate3d rotate rotate3d 等。學習

transform-origin: x-axis y-axis z-axis;  設置旋轉元素的基點位置

transform-style: preserve-3d; 讓轉換的子元素保留3D轉換(與perspective搭配使用)

perspective屬性 --- 讓元素實現3D透視效果

perspective: 1000px;
    它有兩種寫法    
transform: perspective(1000px);

這個屬性讓物體具備立體的3D透視效果, 值越大物體離此時咱們的眼睛看到屏幕裏物體的距離就越遠, 相反若它的值越小, 離咱們的視角就越近, 即在屏幕中顯示的大小就越大。它和preserve-3d共同使用在須要實現3D效果的父元素上搭建舞臺視角, 讓其子元素可以實現真正的3D轉換。動畫

關於transform的詳細講解(張鑫旭)

一個基本的立方體就須要結合以上三點屬性來實現。

Cube

HTML 
<div class="cube-wrap">
    <div class="cube">
        <div class="cube-face front"><img src="1.jpg"></div>
        <div class="cube-face back"><img src="2.jpg"></div>
        <div class="cube-face left"><img src="3.jpg"></div>
        <div class="cube-face right"><img src="4.jpg"></div>
        <div class="cube-face top"><img src="5.jpg"></div>
        <div class="cube-face bottom"><img src="6.jpg"></div>
    </div>
</div>

重要的CSS樣式

CSS
.cube-wrap{
    width: 300px;
    height: 300px;
    perspective: 1000px;
    position: relative;
}
.cube-wrap .cube{
    width: 100%;
    height: 100%;
    position: absolute;
    transform-style: preserve-3d;
    transition: all .5s ease;
}
.cube-wrap .cube .cube-face{
    width: 100%;
    height: 100%;
    position: absolute;
    overflow: hidden;
    opacity: 0.9;
    border: 1px solid #ccc;
}
.cube-wrap .cube .cube-face img{
    width: 100%;
    height: 100%;
}
.cube-face.front{
    transform: translateZ(150px);
}
.cube-face.back{
    transform: rotateX(180deg) translateZ(150px);
}
.cube-face.left{
    transform: rotateY(-90deg) translateZ(150px);
}
.cube-face.right{
    transform: rotateY(90deg) translateZ(150px);
}
.cube-face.top{
    transform: rotateX(90deg) translateZ(150px);
}
.cube-face.bottom{
    transform: rotateX(-90deg) translateZ(150px);
}

在這裏咱們給父元素使用了perspective和preserve-3d, 接下來子元素的3D變換效果纔會生效。

那麼重點來了, 上面的代碼是如何拼接爲一個完整的立方體的呢?在瀏覽器開發者工具裏面仔細觀察一下不難發現, 類名爲cube元素所在位置是在立方體正中間的那一面。所以咱們在如何利用代碼構造立方體的每一面時就有了思路。

首先要清楚, transform相關變換時創建的空間直角座標系x, y , z軸的方向。

即以電腦屏幕爲平面, 水平方向爲x軸, 豎直方向爲y軸, 垂直於屏幕方向的爲z軸。

因此如何構創建方體的六個面就變得很簡單了, cube 面的初始位置在正中間, 整個立方體的長度爲 300px, 所以 translateZ(150px) 即爲正面。要想構造背面, 則先須要逆時針反轉初始面 180deg , 這時候的正面指向背面, 因此只需再 translateZ(150px) 便可。要構造左面則需繞y軸旋轉rotateY(-90deg) , 相應的右側則爲rotateY(90deg) ,而後再進行translateZ(150px) 的平移,剩下的兩個面同理按照相應的邏輯進行便可。 須要注意的是當一個面繞軸轉動時, 逆時針轉動爲正值, 順時針爲負值。

animation屬性

這個屬性在CSS3動畫中確定是最重要的了, 它的每個子屬性都值得咱們去仔細研究。

animation: name duration timing-function delay iteration-count direction fill-mode play-state;

animation-delay: 1s;  設置爲負值時讓動畫立刻開始, 而且跳過1秒前的動畫

animation-direction: normal|reverse|alternate|alternate-reverse; 定義是否循環交替反向播放動畫

alternate 動畫在奇數次(一、三、5...)正向播放, 在偶數次(二、四、6...)反向播放
alternate-reverse 動畫在奇數次(一、三、5...)反向播放, 在偶數次(二、四、6...)正向播放

animation-fill-mode: none|forwards|backwards|both; 規定當動畫不播放時, 要應用到元素的樣式

forwards 動畫結束後停留在最後一幀
backwards 在animation-delay期間啓動動畫的第一幀屬性
both 同時實現forwards與backwards的效果

animation-play-state: paused|running; 控制動畫暫停或運行。

@keyframes 設置動畫關鍵幀, 在這裏咱們用from...to或者百分比來實現自定義的動畫

animation詳解

下面咱們給已經構建好的立方體添加上animation動畫:

CSS
.cube-wrap .cube{
    ......
    animation: spin 10s linear infinite;
}
@keyframes spin {
   from {
       transform: rotateX(45deg) rotateY(45deg);
   }
   to {
       transform: rotateX(405deg) rotateY(765deg);
   }
}

Carousel

如今咱們已經實現了可以自由旋轉的立方體效果了, 接下來就須要完成輪播所具備的基本功能。

  1. 左右按鈕切換

  2. 底部按鈕切換

在實現這兩個功能以前咱們須要瞭解一下兩個強大的HTML標籤, 它們的配合使用實現了輪播圖中點擊切換的效果。它們就是label和input標籤, 先來看看它們的基本用法。

<input type="radio" id="1">

<label for="1" ></label> 點擊label標籤, id爲1的input標籤被選中

這裏label標籤中的for與input標籤中的id相關聯, 而input標籤中type爲radio時是選擇框的效果, 它具備一個checked的屬性 (若要實現單選框的效果, 則須要設置name="xxx" ,此時的名稱要一致, 下文就用到了這個效果)

如今就來開始實現具體的效果吧。

HTML
<div class="container">
    <div class="cube-wrap">
        <input type="radio" name="cuber" class="controller" id="1" checked="true">
        <input type="radio" name="cuber" class="controller" id="2">
        <input type="radio" name="cuber" class="controller" id="3">
        <input type="radio" name="cuber" class="controller" id="4">
        <input type="radio" name="cuber" class="controller" id="5">
        <input type="radio" name="cuber" class="controller" id="6">
        <div class="cube">
          ......
        </div>
        <div class="cube_left">
            <label for="6" class="cube_action"></label>
            <label for="1" class="cube_action"></label>
            <label for="2" class="cube_action"></label>
            <label for="3" class="cube_action"></label>
            <label for="4" class="cube_action"></label>
            <label for="5" class="cube_action"></label>
        </div>
        <div class="cube_right">
            <label for="2" class="cube_action"></label>
            <label for="3" class="cube_action"></label>
            <label for="4" class="cube_action"></label>
            <label for="5" class="cube_action"></label>
            <label for="6" class="cube_action"></label>
            <label for="1" class="cube_action"></label>
        </div>
        <div class="indicators">
            <label for="1" class="indicator"></label>
            <label for="2" class="indicator"></label>
            <label for="3" class="indicator"></label>
            <label for="4" class="indicator"></label>
            <label for="5" class="indicator"></label>
            <label for="6" class="indicator"></label>
        </div>
    </div>
</div>

先實現左右和底部的CSS樣式

CSS
.cube_left .cube_action{
    left: -75px;
    top: 50%;
    transform: translateY(-50%);
}
.cube_right .cube_action{
    right: -75px;
    top: 50%;
    transform: translateY(-50%);
}
.cube_action{
    background-color: #fafafa;
    border-radius: 50%;
    cursor: pointer;
    display: none;
    width: 40px;
    height: 40px;
    opacity: 0.15;
    position: absolute;
    transition: opacity 0.5s ease;
    z-index: 5;
}
.cube_action:hover{
    opacity: 1;
}
.cube_action::before{
    border-bottom: 4px solid #111;
    border-right: 4px solid #111;
    content: '';
    display: block;
    height: 25%;
    left: 50%;
    position: absolute;
    top: 50%;
    width: 25%;
    transform: translate(-70%, -50%) rotate(-45deg);
}
.cube_left .cube_action::before{
    transform: translate(-40%, -50%) rotate(135deg);
}
.indicators{
    position: absolute;
    left: 0;
    right: 0;
    bottom: -80px;
    padding: 20px;
    text-align: center;
    opacity:0;
    transition: opacity .3s;
}
.container:hover .indicators{
    opacity: 1;
}
.indicators .indicator{
    background-color: #fafafa;
    border-radius: 50%;
    cursor: pointer;
    display: inline-block;
    width: 14px;
    height: 14px;
    margin: 6px;
    opacity: .15;
}
.controller{
    display: none;
}

寫完上面的代碼後並不能看到咱們想要的結果, 由於它們都須要hover事件來觸發。

如今咱們來設置最外層 container 的樣式以及定義一個入場動畫。

CSS
.container{
    width: 600px;
    height: 600px;
    position: absolute;
    top: 50%;
    left: 50%;
    margin-top: -300px;
    margin-left: -300px;
    transition: all .5s ease;
    transform: scale(0.25);
}
.container:hover {
    transform: scale(1);
}
.container:hover .cube-wrap .cube{
    animation: entrance .5s ease ;
}
@keyframes entrance {
    from {
        transform: rotateX(-225deg) rotateY(-225deg);
    }
}

當鼠標移入立方體時, 動畫由spin被替換爲entrance 。

那麼重點再次出現了, 到底CSS是如何實現點擊切換輪播圖片的呢?

原理很簡單, 其實就是搭配前面提到的label標籤和input標籤從而實現了驚人的效果。

CSS
.controller:nth-of-type(1):checked ~ .cube{
    transform: translateZ(-150px);
}
.controller:nth-of-type(2):checked ~ .cube{
    transform: translateZ(-150px) rotateX(-180deg) ;
}
.controller:nth-of-type(3):checked ~ .cube{
    transform: translateZ(-150px) rotateY(90deg) ;
}
.controller:nth-of-type(4):checked ~ .cube{
    transform: translateZ(-150px) rotateY(-90deg) ;
}
.controller:nth-of-type(5):checked ~ .cube{
    transform: translateZ(-150px) rotateX(-90deg) ;
}
.controller:nth-of-type(6):checked ~ .cube{
    transform: translateZ(-150px) rotateX(90deg) ;
}

不管是點擊左右的按鈕, 仍是點擊底部的按鈕, 咱們都觸發了label標籤的for屬性從而聯動了對應的input標籤中的checked屬性。

至於該如何將對應的那一面反轉到正對屏幕的這一面, 只須要在構造立方體每一面的轉換中將符號反向便可。

值得注意的是這裏咱們運用的CSS選擇器也算是一個技巧, :nth-of-type(n) 選擇的是相同類型標籤的第n個標籤, ~符號選擇的是同級中的標籤。

完全理解nth-child和nth-of-type的區別

如今咱們回過頭來再仔細看下開頭的HTML結構, indicators 裏面的label標籤中的for好像可以明白其邏輯, 即點擊哪個標籤就觸發哪個input標籤的checked屬性從而進行相應的3D轉換。 但是左右按鈕中的label標籤裏的for數字順序咋看起來不對勁呢?

在這裏我本身也琢磨了好久, 費了很大的功夫纔想明白原來.cube_left或者.cube_right 中相應的6個label標籤是重合在一塊兒的, 並且都爲display:none , 這就頗有意思了, 來看看接下來的代碼。

CSS
.container:hover .controller:nth-of-type(1):checked ~ .cube_left .cube_action:nth-of-type(1), 
.container:hover .controller:nth-of-type(1):checked ~ .cube_right .cube_action:nth-of-type(1){
    display: block;
}
.container:hover .controller:nth-of-type(2):checked ~ .cube_left .cube_action:nth-of-type(2),
.container:hover .controller:nth-of-type(2):checked ~ .cube_right .cube_action:nth-of-type(2){
    display: block;
}
......
......
......
.container:hover .controller:nth-of-type(6):checked ~ .cube_left .cube_action:nth-of-type(6),
.container:hover .controller:nth-of-type(6):checked ~ .cube_right .cube_action:nth-of-type(6){
    display: block;
}

如今咱們默認的是 controller 中的第一個元素被選中, 即它的checked屬性爲true。所以左右按鈕裏label標籤中的第一個顯示爲display:block , 若如今點擊左邊的按鈕, 咱們但願立方體的底部呈如今屏幕的正面, 因此for應該設置爲6。若點擊右邊按鈕其第一個label標籤的for應該設置爲2。按照這個邏輯, 咱們也就明白了爲何.cube_left.cube_right中的for屬性是亂序的緣由了。

至此, 咱們已經講解了如何實現一個旋轉魔方輪播所需的主要內容和知識點, 剩下的就是一些完善界面的零碎的CSS樣式, 在這裏就再也不展現。寫完這篇文章後確實感受本身對CSS方面的知識又熟悉了很多... 可是前端的主力仍是JavaScript, 5月份又得繼續深刻學習JS方面的知識嘞......

PS: 本文參考內容

關於transform的詳細講解(張鑫旭)

animation詳解

完全理解nth-child和nth-of-type的區別

demo的原始出處

相關文章
相關標籤/搜索