CSS3景深、三維變換屬性及旋轉三維立方體的實現

ceco123 8年前發布 | 15K 次閱讀 CSS3 CSS 前端技術

三維立體效果我覺得是CSS3中最有意思的地方,不得不佩服那些開發者大神們,讓我們能夠通過幾行CSS代碼就能得到酷炫的視覺體驗。

瀏覽器坐標系

在講正式語法之前,首先需要了解瀏覽器坐標系,這需要我們把瀏覽器界面想象成一個立體的場景。

這是網上流傳很廣的瀏覽器坐標系圖片,從左到右的方向是瀏覽器x軸的正方向,從上到下的方向是瀏覽器y軸的正方向,而z軸正方向是面對于我們的,了解這個很重要,因為下面我們旋轉元素需要借助它來理解。

3D旋轉

我們在平面中使用的旋轉只是單純的讓元素在平面旋轉一定角度,在三維旋轉中稍微要復雜一些,屬性當然還是用我們的transform,三維旋轉有下面三個函數分別對應三個維度的旋轉:

  • rotateX(xxdeg)
  • rotateY(xxdeg)
  • rotateZ(xxdeg)

rotateX是讓元素繞著x軸旋轉,角度越大,元素繞著x軸順時針旋轉,類似于我們的單杠運動。

transform: rotateX(45deg);

rotateY是讓元素繞著y軸旋轉,角度越大,元素繞著y軸順時針旋轉,類似于鋼管舞運動..

transform: rotateY(45deg);

rotateZ是讓元素繞著z軸旋轉,角度越大,元素繞著z軸順時針旋轉,這就是我們在二維平面的旋轉,類似于轉盤

transform: rotateZ(45deg);

其實3D旋轉還有一個合成的函數是rotate3d(num,num,num,deg),用的不是很多,我就簡單說一下,參數并不是我們想那樣的3個角度值,而是三個數字一個角度值,前三個數字分別表示繞x、y、z軸旋轉的矢量值,最后一個表示在空間的旋轉角度,等價關系如下

rotate3d(1,0,0,xxdeg) <==> rotateX(xxdeg)

rotate3d(0,1,0,xxdeg) <==> rotateY(xxdeg)

rotate3d(0,0,1,xxdeg) <==> rotateZ(xxdeg)

3D位移與3D縮放

我們在2D中用到translateX()和translateY()在平面移動,3D中我們多了translateZ()允許我們沿著z軸平移,同樣可以使用合成函數translate3d(x,y,z),注意前兩個值可以使用百分比形式,但是沿z軸平移的值只能使用長度值。同理我們的3D縮放

scaleX(num)、scaleY(num)、scaleZ(num)、scale3d(num,num,num)

至于它們的用法下面再通過例子來說,(3D的傾斜屬性是不存在的,換句話說,不存在skew3d函數)

透視/景深屬性perspective

景深這個名詞,維基百科是這樣就解釋的

景深(英語:Depth of field, DOF)景深是指相機對焦點前后相對清晰的成像范圍。在光學中,尤其是錄影或是攝影,是一個描述在空間中,可以清楚成像的距離范圍。雖然透鏡只能夠將光聚 到某一固定的距離,遠離此點則會逐漸模糊,但是在某一段特定的距離內,影像模糊的程度是肉眼無法察覺的,這段距離稱之為景深。當焦點設在超焦距處時,景深 會從超焦距的一半延伸到無限遠,對一個固定的光圈值來說,這是最大的景深。

(看到這里,我的手默默的離開了鍵盤,仰天長嘆,心想,這到底要什么樣的學歷才能看得懂)

我們可以這樣來理解,景深就是我們的肉眼距離顯示器的距離,景深越大,元素離我們越遠,效果就不好,在我們CSS3中,perspective用于激活一個3D空間,屬性值就是景深大小(默認none無景深),有兩種用法

.stage {
    perspective: 500px;
}

應用景深的元素稱為“舞臺元素”,舞臺元素的所有后代元素都會受影響,(如果后代元素中也添加了perspective屬性,效果會疊加而不是覆蓋)

<div class="stage">
    <div class="demo"></div>
</div>
.stage {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    margin: 100px auto;
}
.stage .demo {
    width: 200px;
    height: 200px;
    background-color: orangered;
    transform: rotateX(45deg);
}

在這個例子中,我們把內部元素繞x軸旋轉了45°后,由于他只是在二次元旋轉,所以我們根本看不出來它旋轉,但是我們現在加個景深

.stage {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    margin: 100px auto;
    perspective: 500px; /*增*/
}
.stage .demo {
    width: 200px;
    height: 200px;
    background-color: orangered;
    transform: rotateX(45deg);
}

這就相當于我們在舞臺元素的中心位置往里看,這個子元素距離我們肉眼有500px,由于子元素的順時針旋轉,元素上半部分離我們遠,所以看起來很小,元素下半部分離我們近,所以看起來稍大,這樣就會產生很強的立體感

剛才我說道我們的肉眼相當于在舞臺元素中心的位置,其實這個“眼睛”的位置是可以調整的,這用到了perspective-origin屬性,默認的屬性值就是 50% 50%,也就是舞臺元素的中心位置,我們可以嘗試調整視角。

.stage {
    width: 200px;
    height: 200px;
    border: 1px solid black;
    margin: 100px auto;
    perspective: 500px;
    perspective-origin: 10px 10px; /*增*/
}
.stage .demo {
    width: 200px;
    height: 200px;
    background-color: orangered;
    transform: rotateX(45deg);
}

這就相當于在舞臺元素的距離原點(左上)10px,10px的位置往里看,理解這個需要我們一定的空間立體感

注意:景深大小一定要比你的動畫元素大(我們不可能看到眼睛后面的東西)

景深的另一種用法,是應用在動畫元素(不是舞臺元素)變形的函數中,和其他變形函數寫在一起

.stage .demo {
    ......
    transform: rotateX(45deg) perspective(100px);
}

3D屬性transform-style

這個屬性指定了子元素如何在空間中展示,只有兩個屬性值:flat(默認)和preserve-3d,flat 表示所有子元素在2D平面呈現,preserve-3d 表示所有子元素在3D平面呈現,(prederve是保護、維持的意思,preserve-3d就是保持三維空間的意思),當然如果我們想要3D的效果,就要使用 transform-style: preserve-3d;

這個屬性只是針對設置屬性元素的子元素如何展示,而對子元素的子元素無效,而且對于設置了 overflow: hidden; 的元素,設置3D效果會失效,道理很簡單,跳出了父元素平面的子元素無法顯示了,結果自然還是2D效果,應用于這個屬性的元素我們稱作“容器”,這個屬性我們下面通過一個例子再來體會

背面可見屬性backface-visibility

通過這個元素我們可以指定當元素背對我們時是否可見,只有兩個屬性值visibility(默認)和hidden,如果我們希望元素背對我們不可見,就這樣設置

.demo {
    ...
    backface-visibility: hidden;
}

下面我通過一個例子來把上面講到的屬性全部實踐一下

示例:旋轉的三維立方體

<div class="stage">  <!--舞臺元素,視角所在-->
    <ul class="three-d-box">   <!--動畫容器,通過它來控制整個立方體-->
        <li>:capricorn:</li>  <!--動畫元素,立方體的六個面-->
        <li>:virgo:</li>
        <li>:leo:</li>
        <li>:cancer:</li>
        <li>:libra:</li>
        <li>:pisces:</li>
    </ul>
</div>
ul {  /*調整ul標簽的樣式,取消內邊距、外邊距,和“點”樣式*/
    padding: 0;
    margin: 0;
    list-style-type: none;
}
.stage {  /*設置舞臺元素在屏幕居中,設置合適的景深大小*/
    position: relative;
    width: 800px;
    height: 800px;
    margin: 100px auto;
    perspective: 800px;
}
@keyframes move { /*設置動畫關鍵幀*/
    0% {
        transform: rotateX(0deg);
    }
    25% {
        transform: rotateX(180deg);
    }
    50% {
        transform: rotateX(360deg) rotateY(0deg);
    }
    75% {
        transform: rotateX(360deg) rotateY(180deg);
    }       
    100% {
        transform: rotateX(360deg) rotateY(360deg);
    }
}
.stage .three-d-box {  /*動畫容器居中在舞臺元素中間*/
    width: 200px;
    height: 200px;
    position: absolute;
    left: 50%;
    top: 50%;
    margin: -100px 0 0 -100px;
    transform-style: preserve-3d; /*設置3D屬性讓子元素三維空間呈現*/
    animation: move 3s linear infinite; /*設置動畫*/

}
.stage .three-d-box>li { /*設置動畫子元素公共屬性*/
    position: absolute;
    width: 200px;
    height: 200px;
    left: 0;
    top: 0;
    font-size: 50px;
    line-height: 200px;
    text-align: center;
    opacity: 0.5;
}
/*為了保證我們對立方體位置的控制,我們需要讓動畫容器在立方體的中間位置*/
.stage .three-d-box>li:nth-child(1) {
    background-color: red;
    transform: translateZ(-100px);
}
.stage .three-d-box>li:nth-child(2) {
    background-color: greenyellow;
    transform: translateZ(100px);
}
.stage .three-d-box>li:nth-child(3) {
    background-color: cornflowerblue;
    transform: rotateX(90deg) translateZ(100px);
}
.stage .three-d-box>li:nth-child(4) {
    background-color: orangered;
    transform: rotateX(-90deg) translateZ(100px);
}
.stage .three-d-box>li:nth-child(5) {
    background-color: deeppink;
    transform: rotateY(90deg) translateZ(100px);
}
.stage .three-d-box>li:nth-child(6) {
    background-color: lightcoral;
    transform: rotateY(-90deg) translateZ(100px);
}

大功告成

這樣我們就會得到如下酷炫的三維立方體

注意在3D變換transform中,旋轉與位移函數的順序不同,元素展現的位置是不同的,這是因為元素的坐標軸是隨著我們變換而變化的。

上面的代碼如果有不明白的地方,可以拷貝到瀏覽器進行調試,整體的思路就是

  1. 設置舞臺元素(perspective:xxxpx)
  2. 設置動畫容器(transform-style:preserve-3d)
  3. 通過旋轉、位移調整動畫子元素的位置
  4. 對動畫容器應用動畫效果

最后我們通過這個正方體來加深三維變換相關屬性的理解

backface-visibility

添加樣式前的正方體

現在我們來添加樣式

.stage .three-d-box>li {
    ......
    backface-visibility: hidden;
}

大家來找茬,可以看到背對我們的元素全部看不見了,這就是 backface-visibility: hidden; 的作用

 

來自:http://www.webhek.com/css-3d-rotate-cube

 

 本文由用戶 ceco123 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!