CSS3總結七:變換(transform)


  • 2D視圖模型解析
  • 3D視圖模型解析
  • 平移
  • 旋轉
  • 伸縮
  • 扭曲
  • z軸方向平移與perspective的神秘關系
  • matrix()終極變幻的方法

 一、2D視圖

2D視圖就是默認平面上的每個點都與視線垂直,圖形不會隨視角變化發生視圖變形。

 二、3D視圖

3D視圖就是圖形假設了一個視角和透視點,圖形根據視角和透視點,展示圖形在該視角和透視點的變形圖形。

 三、平移

  • translate()
  • translatex()
  • translatey()

平移是基於2D視圖的圖像位置變幻,所以平移不會發生形變。相當於設置了設置定位(position+top/left),但是不會渲染引擎不會渲染平移元素不會放到獨立的渲染層渲染,所以也就不會產生浮動流,且父級元素的overflow可以作用平移的子元素的溢出部分。

 
 
 
 
 

以上示例的關鍵代碼:

 1 /* 示例一 */
 2 /* 沒有什么關鍵代碼,就是兩個普通的嵌套DIV */
 3 /* 示例二 : 基於示例一使用平移實現居中*/
 4 position:absolute;/* 父級設置了relative */
 5 left:calc(50%);
 6 top:calc(50%);
 7 transform:translate(-50%,-50%);
 8 /* 示例三、四 使用平移溢出父級 overflow有效*/
 9 overflow:hidden;/示例四父級DIV/
10 transform:translate(60px,60px); 

需要注意的是translate()是用來設置縱橫坐標同時偏移的方法,如果設置一個參數只有橫向偏移。所以如果需求是一個方向的偏移建議使用translatex()或者translatey()。

 四、旋轉

  • 2D旋轉:rotate()
  • 3D旋轉:rotate3d()、rotatex()、totatey()

關於2D旋轉和3D旋轉需要注意的是,是web的平面圖形基於2D空間和3D空間的旋轉運動,2D空間的旋轉就是在最前面介紹的2D視圖模型的原理,在2D視圖中旋轉的是基於圖形所在平面的某一點做繞該點的旋轉運動。而3D空間的旋轉是基於3D空間的繞空間上的某一條線旋轉,假設視角固定(3D視圖模型),由於圖形的3D旋轉產生視角移動,導致最終我們看到的web界面渲染的圖形所出現的形變效果,這種效果就是transform的3D旋轉效果。

需要注意的是web界面上的3D旋轉模型是圖形所在的平面做旋轉運動,通常我們理解的日常三維空間的旋轉是一個物體圍繞另一個物體運動,運動的物體參照的是另一個物體的三維空間坐標進行運動,但是在web界面中的3D旋轉是基於圖形所在平面自己的三維坐標進行旋轉,由旋轉的圖形在三維空間發生位移而圖形所在的平面同步偏轉位移,所以web中的3D旋轉所基於的三維坐標會同步跟着圖形移動。

簡單的說,就是3D旋轉時坐標軸會跟着圖形旋轉而旋轉,所以在做連續旋轉運動時需要注意所參照的坐標發生的位移問題。

 
 
 
 
 
 
 
 

關於2D旋轉,重點在於旋轉中心的設置(transform-origin),默認的旋轉中心是在元素的中心,也就是示例二、三所表現的樣式。transform-origin(a,b)需要兩個參數,分別是橫向位置、縱向位置;

  • 橫向坐標值:length(距離元素最左側的距離,可以超出元素的寬度)、百分比(基於元素寬度計算)、left(橫向坐標在左側,同length等於0)、right(元素的最右側,同length等於寬度)。
  • 縱向坐標的值:length、百分比、top、bottom。

示例中的關鍵代碼:

 1 /*示例一省略*/
 2 /*示例二*/
 3 transform:rodate(45deg);
 4 transform-origin:50% 50%;/*默認值同等與center center*/
 5 /*示例三*/
 6 @keyframes run{
 7        0%{transform:rodate(0deg)}
 8        100%{transform:rodate(360deg)}
 9 }
10 animation:run 20s cubic-bezier(0,0,1,1) infinite;
11 /*示例四*/
12 @keyframes run1{
13        0%{transform:rodate(30deg)}
14        100%{transform:rodate(60deg)}
15 }
16 left:50%;
17 transform-origin:0px 0px:
18 transform:rotate(30deg);
19 animation:run1 1.5s cubic-bezier(0,0,1,1) infinite alternate;

雖然2D視圖的旋轉效果比較簡單,但是重點並不在於應用2D視圖,首先我們需要通過2D旋轉來了解一個web視圖基礎知識,就是坐標原點和坐標方向。雖然在上面的四個示例中不能直接看到這其中的規律,但是還是可以推斷出在web中的坐標方向y軸與我們通常的數學物理中的坐標軸方向不一致,在web視圖中的y軸方向是指向下方的。

關於設置旋轉中心transform-origin我們只能設置x軸和y軸的坐標,z軸默認始終是0。z軸更關鍵的是在於設置3D變換的視距,如果不設置3D視覺的話,圖形發生的3D旋轉在web界面上表現的視圖是由2D視圖模型看到的圖形因為旋轉發生寬高伸縮變換,並非3D視圖變換,具體有什么區別通過以下幾個示例來了解。

 
 
 
 

以上四個示例用來比較解析2D視圖扭曲3D旋轉與3D視圖的3D旋轉的區別,另外又通過示例三、四對比出視距對3D視圖展示的影響。首先需要了解幾個重要的CSS3屬性:

  • transform:rotateY();/*3D旋轉中心軸*/
  • transform-origin:length length;/*2D旋轉中已經解析過*/
  • perspective:length;透視距離
  • transform-style:preserve-3d/flat;/*設置圖形位於3維空間(3D視圖)還是圖形所在平面的扁平化處理(2D視圖扭曲的3D旋轉)*/

再來看示例中的關鍵代碼:

 1 /*示例一省略*/
 2 /*示例二*/
 3 transform:rotateY(45deg);/*以Y軸為旋轉軸,順時針轉45°*/
 4 transform-origin:50% 50%;/*默認值*/
 5 /*示例三*/
 6 perspective:100px;/*默認視線在z軸方向上距離旋轉中心的距離-設置在父級元素上*/
 7 transform-style: preserve-3d;
 8 transform-origin:50% 50%;/*默認旋轉中心*/
 9 transform:rotateY(45deg);
10 /*示例四:相對示例三只有視距發生變化*/
11 perspective:300px;

這里有一個有意思的地方,或者說需要注意的地方,當使用transform:rotateX/rotateY/rotate3d時,必須要設置視距perspective的實現距離,這個屬性不能設置0像素或者是負像素值,只有設置了perspective大於0像素的視距3D旋轉視圖才會有效,不然展示出來的視圖就是2D視圖下的3D旋轉扭曲圖形(如示例二)。

然而,我測試transform-style時,不論設置三維空間與否,如果不設置perspective的視距都不會有任何變化,但是如果設置了perspective的視距但不設置transform-style會正常出現3D視圖,也就是說我測試的結果是transform-style實質上沒有任何意義,是否有三維空間視圖取決於perspective的控制,這個地方我暫時沒有找到合理的解釋,如果有知道的朋友還請不吝指教。

旋轉與坐標    
 
 
 
 
 

 關鍵代碼:

1 /*示例二*/
2 transform:rotateY(45deg);
3 /*示例三*/
4 transform:rotateY(45deg) rotateX(45deg);
5 /*示例四*/
6 transform:rotateY(45deg) rotateX(45deg) rotateZ(45deg);
7 /*示例五*/
8 transform: rotate3d(0, 10, 0, 45deg) rotate3d(10, 0, 0, 45deg) rotate3d(0, 0, 10, 45deg);

圖解旋轉與坐標的關系:

 

 

由代碼示例展示到圖解分析,還記得我在旋轉部分開始文字解析的時候就說過的,3D旋轉變換時實質上是圖形所在平面繞旋轉軸旋轉,坐標永遠都會跟隨平面的旋轉而旋轉。

最后還是提一下關於rotate3d()這個函數吧,這個函數可以實現自定義旋轉軸,如果只在一個坐標軸方向設置參數就表示以該坐標軸為旋轉中心,參數大小無關(只要不等於0);如果設置多個坐標方向的參數,就會以設定的坐標參數大小來計算出自定義的旋轉軸,這需要一些幾何知識,三維空間的物理知識或許更准確,這些都不重要,重要的是你還記得這些高中時的知識。

 五、伸縮變換、與對平移的影響

  • scale()
  • scalex()
  • scaley()
  • scalez()
  • scale3d()

關於伸縮變換方法需要注意的就是元素視圖伸縮后,在當前作用視圖的平面上保留伸縮狀態,如果圖形發生其他視圖變換,變換后的圖形視圖會因為之前的平面伸縮發生伸縮變換。這種影響主要可以從兩種情況來理解,比如圖形視圖在x軸方向發生伸長2倍操作,接着觸發x軸方向的平移,這時候平移的實際距離是設定參數的2倍;第二種情況就是當視圖還是x軸發生2倍伸長,然后接着元素圖形發生2D變換旋轉90°,這時候旋轉后的圖形Y軸就與之前的X軸平行了,所以旋轉后的圖形Y軸方向會作用之前視圖X軸的2倍伸長。用下面的兩個示例來理解。

在展示示例之前還需要注意的是,元素圖形伸縮是基於變換中向四周伸縮的,所以默認的變換中心在元素的中心點上,圖形就會基於中心點向四周拉伸。

1.下面來展示第一種情況,伸縮變換scale()對平移translate()產生的影響:

 
 

實現效果的關鍵代碼:

1 /*示例一沒有任何變換屬性的100*100的div*/
2 /*示例二 寬高100px 變換中心設置為0px 0px(左上角),橫向伸長一倍,平移100px*/
3 transform-origin:0px 0px;
4 transform:scale(2,1) translateX(100px);

2.伸縮變換對旋轉后的圖形的影響:

 
 
 

 這個示例我將富文本內編輯的示例代碼全部貼出來對比(規律在前面已經解析過了,就不重復了):

1 <div style="width: 100px; height: 100px; background-image: linear-gradient(to left,#CD853F, #CD69C9);">&nbsp;</div>
2 <div style="width: 100px; height: 100px; background-image: linear-gradient(to left,#CD853F, #CD69C9); transform-origin: 100px 100px; transform: scale(2,1); margin-left: 100px; margin-top: 10px;">&nbsp;</div>
3 <div style="width: 100px; height: 100px; background-image: linear-gradient(to left,#CD853F, #CD69C9); transform-origin: 100px 100px; transform: scale(2,1) rotate(90deg); margin-left: 100px; margin-top: 10px;">&nbsp;</div>

最后關於變換伸縮,我在解析中使用的是視圖平面拉伸,也有說成是視圖的坐標拉伸,其描述的都是元素圖形所在平面的伸縮變換。

然后關於關於scalez()或者scale3d()是z軸方向的拉伸,但由於web視圖是2D圖形,沒有厚度,所以在2D試圖變換中不會產生變化,但是在3D旋轉視圖變化中就會產生作用了。變化規律依然不變。

 六、扭曲變換與坐標的關系及對其他變換的影響

  • skew()
  • skewx()
  • skewy()

橫向扭曲相當於拉伸x軸方向上的兩條邊向兩邊移位,導致y軸傾斜並被拉伸,反之縱向扭曲相當於y軸方向上的兩條邊向兩邊移位,導致x軸傾斜被拉伸。先來看圖解:

所以被橫向扭曲的圖形如果在發生y軸方向的平移就是一個傾斜的平移,同理基於y軸的旋轉也會是一個傾斜的旋轉。

 
 
 
 

接着來看一個skew()在縱橫兩個方向上同時出現扭曲的變換:

 

 關鍵代碼:

1 @keyframes skew3{
2     0%{transform:skew(0deg, 0deg)}
3     25%{transform:skew(45deg, 45deg)}
4     50%{transform:skew(0deg ,0deg)}
5     75%{transform:skew(-45deg ,-45deg)}
6     100%{transform:skew(0deg ,0deg)}
7 }
8 animation: skew3 5s cubic-bezier(0,0,1,1) infinite;

這種扭曲變形所產生的空間感是由視覺的錯覺產生的,並非采用3D視圖。

 七、z軸方向平移與perspective的神秘關系

7.1在第三部分內容解析了關於2D平移的變換,在2D變換中,視圖不會出現形變,只產生位置變化。但是在Z軸方向上的平移變換就是由視距perspective共同產生作用,正常情況下我們所理解的視距與視圖的變換都是近大遠小,但是在屏幕視圖中,我們所看到的圖像是模擬三維空間中圖像在屏幕上的投影。所以在不設定Z軸平移transform:translateZ()時就默認圖形與屏幕所在的平面重合,在這種情況下移動視距perspective屏幕中的圖像不會發生任何變化。因為屏幕不會隨視線距離產生變化。

如果translateZ()的參數大於0時,就相當於圖形遮擋在屏幕前面,所以視距越接近圖形,圖形在屏幕上的投影就會越大,如果視線與屏幕的距離小於圖形在Z軸中上的正向移動距離,圖形就會消失。

如果translateZ()參數小於0時,就相當於圖形在屏幕的后方,屏幕上所呈現的視圖只是視線與圖形的視角的一個切面,這時候會因為視距越近,視角越小,導致圖形在屏幕上的切面越小。簡單地說就是圖形translateZ()的參數小於0時,視距越小,視圖越小。

 
 
 

 關鍵代碼:

 1 @keyframes pers{
 2      0%{perspective:1000px;}
 3      100%{perspective:100px;}
 4 }
 5 /*父級元素*/
 6 perspective:1000px;
 7 animation:pers 5s cubic-bezier(0,0,1,1) infinite;
 8 /*示例一默認*/
 9 /*示例二*/
10 transform:translateZ(60px);
11 /*示例三*/
12 transform:translateZ(-60px);

7.2原來transform-style是這么用的:

當兩個DIV嵌套,並設置子元素在Z軸上向正方向平移一段距離,然后旋轉父級DIV,從3D視圖的邏輯上來說這時候可以看到父子元素之間會出現Z軸上的距離,但是由於默認的瀏覽器渲染模式下旋轉的元素和其子元素是保持在一個平面上渲染的,所以默認情況下只能看到子元素的旋轉效果。在這種情況下CSS3提供了transform-style屬性來改變元素內部的空間渲染模式,但設置transform-style: preserve-3d時就可以出現父子元素保持了Z軸方向上的空間距離,在旋轉上就可以同時看到父子元素了。

 
 

 

1 <div style="width: 100%; display: flex; flex-wrap: wrap; perspective: 800px; justify-content: center; align-items: center;">
2 <div style="widht: 100px; height: 100px; background-color: red; transform: rotateY(25deg);">
3 <div style="width: 100px; height: 100px; background-color: blue; transform: translateZ(100px);">&nbsp;</div>
4 </div>
5 <div style="widht: 100px; height: 100px; margin-left: 50px; background-color: red; transform: rotateY(25deg); transform-style: preserve-3d;">
6 <div style="width: 100px; height: 100px; background-color: blue; transform: translateZ(100px);">&nbsp;</div>
7 </div>
8 </div>

7.3原來transform-origin可以定義3維旋轉中心!!!

 

 

 

 

 

這里展示的是一個2維視圖效果,3維視圖效果見代碼,關鍵的一行代碼在這里:transform-origin: 100px 0px -500px;

 1 <style>
 2     *{
 3         margin: 0;
 4         padding: 0;
 5     }
 6     :root
 7     ,body{
 8         height: 100%;
 9         perspective: 800px;
10     }
11     @keyframes origin3w{
12         0%{
13             transform: rotateY(0deg) ;
14         }
15         50%{
16             transform: rotateY(180deg) ;
17         }
18         100%{
19             transform: rotateY(360deg) ;
20         }
21     }
22     div{
23         position: absolute;
24         top: calc(50% - 50px);
25         left: calc(50% - 50px);
26         width: 100px;
27         height: 100px;
28         background-size: cover;
29         transform-origin: 100px 0px -500px;
30         border-radius: 50px;
31         background-color: red;
32         animation: origin 10s cubic-bezier(0,0,1,1) infinite;
33     }
34 </style>
35 <div ></div>
View Code

 八、matrix()終極變幻的方法

了解matrix()函數之前,必須先了解以下矩陣,在matrix()中只應用到了乘法矩陣,所以接下來也只針對乘法矩陣加以說明。矩陣在數學中的定義就是一個用來排列復數和實數的集合,在這里我們暫時不必要去研究復數和實數這些數學理論,我們只需要知道矩陣在matrix()中的應用就相當於一個用來存儲數據的數據單元,那它怎么存儲數據呢?先來看一些例子:

上面的示例中就是兩個矩陣,第一個矩陣叫做三行三列矩陣,第二個矩陣叫做三行一列矩陣。接着來看什么是乘法矩陣(為了更好的表達乘法矩陣采用字母替代數值來表示):

相信你已經發現規律了,所謂的乘法矩陣就是第一個矩陣的橫向數據乘以對應的第二個縱向數據的和就得到了一個新的矩陣。如果第二個矩陣是兩列的話,計算得到的矩陣就是兩列的矩陣。來看下面這個示例:

在矩陣中的表示方法不存在逗號,這里為了更好的展示和理解我添加上了逗號,這個不是重點,重點是在matrix()中的第二個矩陣只需要一列就夠了,不會出現上面這個相對復雜一些的矩陣。那再matrix()中需要怎么樣的矩陣呢?又是怎么應用的呢?下面來看一組乘法矩陣轉化成matrix()的計算邏輯和transform變換的應用:

看到這個乘法矩陣是不想到了什么?先不要看第一個矩陣,看后面兩個,第二個矩陣的x和y可以用來表示在平面上的一個點的坐標。假設x和y表示了某個圖形的一個像素點,那么e就表示這個像素點在x軸方向的平移距離,f就表示這個點在y軸方向上的平移距離。

x和y是我們已知的圖形的,e和f就是我們要對圖形變換在平面內進行平移操作的橫向和縱向的距離。再回頭來看第一個矩陣,這就是我們需要在matrix的參數。

transform:matrix(1,0,0,1,e,f); ===>同等與transform:translate(epx,fpx);

 

matrix()的取值就是在第一組矩陣中的上面兩行獲取的,至於為什么會有第三行,后面你就知道了,在平面變換中暫時只需要前面兩行。通過上面的示例我們推導出matrix實現transform的平移公式。接着來看伸縮是不是就很簡單了,transform:matrix(a,0,0,b,0,0); ===>同等與transform:scale(a,b);

然后來個有點夢幻的:

別飄,這是rotate()的乘法矩陣,實在是不敢吹牛了,給個鏈接大家自己看着辦吧https://www.cnblogs.com/Ivy-s/p/6786622.html。

但是我依然沒有有關於z軸的變換矩陣解析,這種夢幻的東西還是留給數學高手來解決吧。凌晨兩點半了,睡覺。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM