前言
在css3中允許使用3D轉換來對元素進行格式化,在原本只是2D轉化的平面中引入了Z軸。在這之前我們講解了css3中的2D轉換,也就是二維空間變換,本篇的3D轉換就是基於原來的2D轉換而來,與2D轉換的功能相似。
三維座標系
相信學過數學的效果版對這一概念多多少少是知道的,我們要想有一個3D空間效果,也就是立體空間感,比如:正方體、長方體.....再比如我們生活所居住的房間也是3D立體空間的,主要有X軸、Y軸Z軸共同組成
x軸 : 水平向右,x右邊是正值,左邊是負值。
y軸 : 垂直向下,y下面是正值,上面是負值。
z軸 : 垂直螢幕,往外面是正值,往裡面是負值。
轉換屬性
屬性 | 描述 |
transform | 使得元素向2D或3D轉換 |
transform-origin | 改變轉換元素的位置 |
transform-style | 規定被巢狀元素如何在 3D 空間中顯示 |
perspective | 規定 3D 元素的透視效果 |
perspective-origin | 規定 3D 元素的底部位置 |
backface-visibility | 定義元素在不面對螢幕時是否可見 |
這裡transform
屬性和transform-origin
屬性在前一篇《有趣的transform形變》中已經講解了,這裡就不再細說。不同的是在3D轉換中,transform-origin
屬性會接收第三個值,表示Z軸方向位置
(1)transform-style
transform-style
設定元素的子元素是位於 3D 空間中還是平面中。
語法:
div{ transform-style: flat|preserve-3d; }
- flat:設定元素的子元素位於該元素的平面中(子元素不設定3D空間)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .box{ position: relative; width: 200px; height: 200px; margin: 100px auto; transition: .5s; /* flat:子元素不存在3D空間 */ transform-style: flat; background-color: #eee; } .box:hover{ transform: rotateY(60deg); } .s{ position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: pink; } .s2{ background-color: orange; transform: rotateX(45deg); } </style> </head> <body> <div class="box"> <div class="s s1"></div> <div class="s s2"></div> </div> </body> </html>
設定flat值,子元素就只位於平面中,效果如下:
- preserve-3d:設定元素的子元素應用於3D空間中
基於上述栗子,將transform-style
屬性值改為preserve-3d
:
.box{ /* 讓子元素保持3d立體空間環境 */ transform-style: preserve-3d; }
得到3D空間效果:
3D視覺是不是感覺一下就來啦~
(2)perspective
perspective
指定了觀察者與 z=0 平面的距離,使具有三維位置變換的元素產生透視效果。如果不指定透視,則Z軸空間中的所有點將平鋪到同一個2D視平面中,並且變換結果中將不存在景深概念z>0 的三維元素比正常大,而 z<0 時則比正常小,大小程度由該屬性的值決定
“perspective”本身就具有透視的意思,就是設定用於戶和元素3D空間Z平面之間的距離(視距),簡單理解就是將電腦螢幕當做一個平面,使用者眼睛到螢幕的垂直方向。值越大使用者與螢幕距離越遠,視覺效果很小,值越小3D效果就越明顯。
語法:
div{ perspective:none | <length> }
- none:預設值,與 0 相同,不設定透視
- length:元素距離檢視的距離,以畫素計
這裡還是以上述栗子進行演示:
body{ perspective: 900px; }
或者
.box{ perspective: 900px; }
只要設定在父盒子上就可以,效果如下:
從第一眼就可以看出與上面不同,沒有設定景深是這樣:
設定了景深是這樣的:
注意:perspective-origin
屬性,可以改變 3D 元素的底部位置
(3)perspective-orgin
perspective-origin 屬性定義 3D 元素所基於的 X 軸和 Y 軸。該屬性允許您改變 3D 元素的底部位置。
語法:
perspective-origin: x-axis y-axis;
x-position:指定消失點的橫座標,其值有以下形式:
<length-percentage>
長度值或相對於元素寬度的百分比值,可為負值。left
, 關鍵字,0值的簡記。center
, 關鍵字,50%的簡記。right
, 關鍵字,100%的簡記。
y-position:指定消失點的縱座標,其值有以下形式:
<length-percentage>
長度值或相對於元素高度的百分比值,可為負值。top
, 關鍵字,0值的簡記。center
, 關鍵字,50%的簡記。bottom
, 關鍵字,100%的簡記
介紹完語法使用,我們知道了怎麼取值,下面還是基於上述例子繼續演示:
- 值為長度值:
.box{ perspective-origin: 300px; }
效果如下:
- 值為關鍵字:
.box{ perspective: 900px; perspective-origin: left; }
效果如下:
- 值為百分比:
.box{ perspective: 900px; perspective-origin: 300%; }
效果如下:
- 兩個值:
.box{ perspective: 900px; perspective-origin: left top; }
效果如下:
(4)backface-visibility
backface-visibility
指定當元素背面朝向觀察者時是否可見
元素的背面是其正面的映象,雖然在 2D 中不可見,但是當變換導致元素在 3D 空間中旋轉時,背面可以變得可見。 (此屬性對 2D 變換沒有影響,它沒有透視。)
語法:
backface-visibility: visible|hidden;
- visible:預設值。 背面是可見的。
- hidden:背面是不可見的
這裡借鑑了MDN上面的例子:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Document</title> <style> .showbf div { backface-visibility: visible; } .hidebf div { backface-visibility: hidden; } .container { width: 150px; height: 150px; margin: 75px 0 0 75px; border: none; } .cube { width: 100%; height: 100%; perspective: 550px; perspective-origin: 150% 150%; transform-style: preserve-3d; } .face { display: block; position: absolute; width: 100px; height: 100px; border: none; line-height: 100px; font-family: sans-serif; font-size: 60px; color: white; text-align: center; } .front { background: rgba(0, 0, 0, 0.3); transform: translateZ(50px); } .back { background: rgba(0, 255, 0, 1); color: black; transform: rotateY(180deg) translateZ(50px); } .right { background: rgba(196, 0, 0, 0.7); transform: rotateY(90deg) translateZ(50px); } .left { background: rgba(0, 0, 196, 0.7); transform: rotateY(-90deg) translateZ(50px); } .top { background: rgba(196, 196, 0, 0.7); transform: rotateX(90deg) translateZ(50px); } .bottom { background: rgba(196, 0, 196, 0.7); transform: rotateX(-90deg) translateZ(50px); } th, p, td { background-color: #EEEEEE; margin: 0px; padding: 6px; font-family: sans-serif; text-align: left; } </style> </head> <body> <table> <tr> <th><code>backface-visibility: visible;</code></th> <th><code>backface-visibility: hidden;</code></th> </tr> <tr> <td> <div class="container"> <div class="cube showbf"> <div class="face front">1</div> <div class="face back">2</div> <div class="face right">3</div> <div class="face left">4</div> <div class="face top">5</div> <div class="face bottom">6</div> </div> </div> <p> Since all faces are partially transparent, the back faces (2, 4, 5) are visible through the front faces (1, 3, 6). </p> </td> <td> <div class="container"> <div class="cube hidebf"> <div class="face front">1</div> <div class="face back">2</div> <div class="face right">3</div> <div class="face left">4</div> <div class="face top">5</div> <div class="face bottom">6</div> </div> </div> <p> The three back faces (2, 4, 5) are hidden. </p> </td> </tr> </table> </body> </html>
3D轉換
旋轉單位:deg(角度)、rad(弧度)、grad(梯度)、turn(圈)
(1)3D位移
3D位移在2D基礎上多加了一個可以z軸移動的方向
3D位移主要演示
兩個屬性:translate3d()
CSS 函式在3D空間內移動一個元素的位置,這個移動由一個三維向量來表達,分別表示他在三個方向上移動的距離
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>3D位移</title> <style> body{ perspective: 800px; } .box{ position: relative; width: 200px; height: 200px; margin: 100px auto; transition: .5s; background-color: pink; text-align: center; line-height: 200px; } .box:hover{ /* transform: translateX(50px) translateY(100px) translateZ(200px); */ /* 簡寫 */ transform: translate3d(50px,100px,200px); } </style> </head> <body> <div class="box">3D位移</div> </body> </html>
效果如下:
注意:
- 首先要設定
perspectiv
屬性在被觀察元素的父盒子上,不然不會有Z軸效果。 - 如果只是單獨設定Z軸視距,可以直接使用translateZ屬性。
- Z軸設定的值越大,距離我們眼睛就越近,也就是簡單理解元素被放大了
- Z軸設定的值越小,或者為負數,則會離我們眼睛越遠,元素縮小
(2)3D旋轉
rotateX:讓元素圍繞X軸轉
rotateY:讓元素圍繞Y軸旋轉
rotateZ:讓元素圍繞Z軸旋轉
rotate3d:讓元素圍繞固定軸旋轉不變形
旋轉量由角度決定,角度為正則順時針旋轉,反之逆時針旋轉
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>3D旋轉</title> <style> body{ perspective: 800px; } .box{ position: relative; width: 200px; height: 200px; margin: 100px auto; transition: .5s; background-color: pink; text-align: center; line-height: 200px; } .box:hover{ transform: rotateX(180deg); /* X軸旋轉180° */ transform: rotateY(180deg); /* Y軸旋轉180° */ transform: rotateZ(180deg); /* Z軸旋轉180° */ } </style> </head> <body> <div class="box">3D旋轉</div> </body> </html>
X軸旋轉效果:
Y軸旋轉效果:
Z軸旋轉效果:
這裡單獨將rotate3d函式拎出來講
語法:
rotate3d(x, y, z, a)
取值分析:
- x:可以是0到1之間的數值,表示旋轉軸X座標方向的向量
- y:可以是0到1之間的數值,表示旋轉軸Y座標方向的向量
- z:可以是0到1之間的數值,表示旋轉軸Z座標方向的向量
- a:表示旋轉角度。正的角度值表示順時針旋轉,負值表示逆時針旋轉
也就是說 rotateX(a) === rotate3d(1,0,0,a) 、 rotateY(a) === rotate3d(0,1,0,a) 、 rotateZ(a) === rotate3d(0,0,1,a)
.box:hover{ transform: rotate3d(1,1,0,50deg); /* 表示在X軸和Y軸旋轉50° */ }
效果如下:
.box:hover{ transform: rotate3d(1,1,1,1turn); /* 圍繞3軸旋轉一圈 */ }
效果如下:
綜合案例
基於上述所學內容,我們來實操做一個3D盒子旋轉:
html結構 :
<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>3D盒子旋轉</title> <link rel="stylesheet" href="css/index.css" /> </head> <body> <section> <div><img src="images/1.jpg" alt="" /></div> <div><img src="images/2.jpg" alt="" /></div> <div><img src="images/3.jpg" alt="" /></div> <div><img src="images/4.jpg" alt="" /></div> <div><img src="images/5.jpg" alt="" /></div> <div><img src="images/6.jpg" alt="" /></div> <div><img src="images/1.jpg" alt="" /></div> <div><img src="images/2.jpg" alt="" /></div> <div><img src="images/3.jpg" alt="" /></div> <div><img src="images/4.jpg" alt="" /></div> <div><img src="images/5.jpg" alt="" /></div> <div><img src="images/6.jpg" alt="" /></div> </section> </body> </html>
css部分 :
* { /* 初始化 */ padding: 0; margin: 0; } body { /* 彈性佈局*/ display: flex; justify-content: center; align-items: center; height: 100vh; /* 視距 */ perspective: 1000px; } section { position: relative; width: 150px; height: 150px; /* 讓子元素保留其3D位置 */ transform-style: preserve-3d; /* 動畫 名稱 時長 linear 是勻速運動 infinite是無限次播放 */ animation: rotate 5s linear infinite; } section div { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background-color: #fff; transition: all 1s; } section div img { width: 100%; height: 100%; } /* 這裡使用的偽類選擇器 */ section div:nth-child(1) { /* 選擇第1個元素 */ transform: translateZ(75px); } section:hover div:nth-child(1) { transform: translateZ(200px); } section div:nth-child(2) { /* 選擇第2個元素 */ transform: rotateX(-180deg) translateZ(75px); } section:hover div:nth-child(2) { transform: rotateX(-180deg) translateZ(200px); } section div:nth-child(3) { /* 選擇第3個元素 */ transform: rotateX(90deg) translateZ(75px); } section:hover div:nth-child(3) { transform: rotateX(90deg) translateZ(200px); } section div:nth-child(4) { /* 選擇第4個元素 */ transform: rotateX(-90deg) translateZ(75px); } section:hover div:nth-child(4) { transform: rotateX(-90deg) translateZ(200px); } section div:nth-child(5) { /* 選擇第5個元素 */ transform: rotateY(90deg) translateZ(75px); } section:hover div:nth-child(5) { transform: rotateY(90deg) translateZ(200px); } section div:nth-child(6) { /* 選擇第6個元素 */ transform: rotateY(-90deg) translateZ(75px); } section:hover div:nth-child(6) { transform: rotateY(-90deg) translateZ(200px); } section div:nth-child(7) { /* 選擇第7個元素 */ transform: translateZ(75px); } section div:nth-child(8) { /* 選擇第8個元素 */ transform: rotateX(-180deg) translateZ(75px); } section div:nth-child(9) { /* 選擇第9個元素 */ transform: rotateX(90deg) translateZ(75px); } section div:nth-child(10) { /* 選擇第10個元素 */ transform: rotateX(-90deg) translateZ(75px); } section div:nth-child(11) { /* 選擇第11個元素 */ transform: rotateY(90deg) translateZ(75px); } section div:nth-child(12) { /* 選擇第12個元素 */ transform: rotateY(-90deg) translateZ(75px); } /* 定義動畫 */ @keyframes rotate { 0% { transform: rotateY(0) rotateX(0); } 100% { transform: rotateY(360deg) rotateX(360deg); } }
效果如下