css3帶你實現3D轉換效果

newknight發表於2022-03-01

前言

在css3中允許使用3D轉換來對元素進行格式化,在原本只是2D轉化的平面中引入了Z軸。在這之前我們講解了css3中的2D轉換,也就是二維空間變換,本篇的3D轉換就是基於原來的2D轉換而來,與2D轉換的功能相似。

三維座標系

相信學過數學的效果版對這一概念多多少少是知道的,我們要想有一個3D空間效果,也就是立體空間感,比如:正方體、長方體.....再比如我們生活所居住的房間也是3D立體空間的,主要有X軸、Y軸Z軸共同組成

css3帶你實現3D轉換效果

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值,子元素就只位於平面中,效果如下:

css3帶你實現3D轉換效果

  • preserve-3d:設定元素的子元素應用於3D空間中

基於上述栗子,將transform-style 屬性值改為preserve-3d :

.box{
  /* 讓子元素保持3d立體空間環境 */
  transform-style: preserve-3d;
}

得到3D空間效果:

css3帶你實現3D轉換效果

3D視覺是不是感覺一下就來啦~

(2)perspective

perspective指定了觀察者與 z=0 平面的距離,使具有三維位置變換的元素產生透視效果。如果不指定透視,則Z軸空間中的所有點將平鋪到同一個2D視平面中,並且變換結果中將不存在景深概念

z>0 的三維元素比正常大,而 z<0 時則比正常小,大小程度由該屬性的值決定

“perspective”本身就具有透視的意思,就是設定用於戶和元素3D空間Z平面之間的距離(視距),簡單理解就是將電腦螢幕當做一個平面,使用者眼睛到螢幕的垂直方向。值越大使用者與螢幕距離越遠,視覺效果很小,值越小3D效果就越明顯。

css3帶你實現3D轉換效果

語法

div{
   perspective:none | <length>
}
  • none:預設值,與 0 相同,不設定透視
  • length:元素距離檢視的距離,以畫素

這裡還是以上述栗子進行演示:

body{
    perspective: 900px;
} 

或者

.box{
    perspective: 900px;
}

只要設定在父盒子上就可以,效果如下:

css3帶你實現3D轉換效果

從第一眼就可以看出與上面不同,沒有設定景深是這樣:

css3帶你實現3D轉換效果

 設定了景深是這樣的:

css3帶你實現3D轉換效果

 注意perspective屬性隻影響 3D 轉換元素,並且同時使用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;
}

效果如下:

css3帶你實現3D轉換效果

  • 值為關鍵字:
.box{
    perspective: 900px;
    perspective-origin: left;
}

效果如下:

css3帶你實現3D轉換效果

  • 值為百分比:
.box{
    perspective: 900px;
    perspective-origin: 300%;
}

效果如下:

css3帶你實現3D轉換效果

  • 兩個值:
.box{
    perspective: 900px;
    perspective-origin: left top;
}

效果如下:

css3帶你實現3D轉換效果

(4)backface-visibility

backface-visibility 指定當元素背面朝向觀察者時是否可見

元素的背面是其正面的映象,雖然在 2D 中不可見,但是當變換導致元素在 3D 空間中旋轉時,背面可以變得可見。 (此屬性對 2D 變換沒有影響,它沒有透視。)

語法:

backface-visibility: visible|hidden;
  • visible:預設值。 背面是可見的。
  • hidden:背面是不可見的

這裡借鑑了MDN上面的例子:

css3帶你實現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>
        .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>
View Code

 

3D轉換

旋轉單位:deg(角度)、rad(弧度)、grad(梯度)、turn(圈)

  • 弧度 = 角度*π/180

  • grad = 360度(一圈)

(1)3D位移

3D位移在2D基礎上多加了一個可以z軸移動的方向

3D位移主要演示translateZtranslate3d兩個屬性:

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>

效果如下:

css3帶你實現3D轉換效果

注意

  • 首先要設定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軸旋轉效果:

css3帶你實現3D轉換效果

Y軸旋轉效果:

css3帶你實現3D轉換效果

Z軸旋轉效果:

css3帶你實現3D轉換效果

這裡單獨將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° */
}

效果如下:

css3帶你實現3D轉換效果

 

.box:hover{
    transform: rotate3d(1,1,1,1turn); /* 圍繞3軸旋轉一圈 */
}

效果如下:

css3帶你實現3D轉換效果

 

綜合案例

基於上述所學內容,我們來實操做一個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);
    }
}

 效果如下 

 css3帶你實現3D轉換效果

 

相關文章