CSS 3 學習——transform 3D轉換渲染

如下內容根據官方規範翻譯,沒有翻譯關於SVG變換的內容和關於矩陣計算的內容。css

通常狀況下,元素在一個無景深無立體感的平面(flat plane)上渲染,這個平面就是其包含塊所處的平面。同時,頁面上的其餘元素也共享這個平面。2D變換函數雖然能改變元素的表現,可是這個被改變的元素仍然是在其包含塊所處的平面內被渲染。html

3D變換會產生一個變換矩陣,該變換矩陣在Z軸上的份量不爲0。結果是把元素渲染到一個不一樣於其包含塊所處的平面內。這將影響到一般狀況下的「後來居上」的渲染規則:變換元素可能會和其相鄰的其餘元素相互交叉。css3

例子web

這個例子演示了3D變換對一個元素的影響。segmentfault

 1 <style>
 2 div {
 3     height: 150px;
 4     width: 150px;
 5 }
 6 .container {
 7     border: 1px solid black;
 8 }
 9 .transformed {
10     transform: rotateY(50deg);
11 }
12 </style>
13 
14 <div class="container">
15     <div class="transformed"></div>
16 </div>

例子中藍色div進行了一個繞着Y軸旋轉50deg的旋轉變換,從結果來看,藍色div僅僅是變窄了,並無3D效果,由於變換仍是在無景深無立體感的2D平面上進行的,還需接着往下看。數組

 

Perspective 透視

perspective和perspective-origin屬性能給舞臺(scene,變換元素所處的空間)添加縱深感,結果就是元素距離觀看者越近就表現得越大,越遠就表現得越小(經過變換能夠改變元素在Z軸上的位置)。瀏覽器

perspective屬性指定觀看者的眼睛(假設的)與屏幕 (drawing plane)之間的距離。若是將perspective屬性的值設爲d,則元素的縮放比例就等於d/(d − z),z是元素在Z軸上的位置,更準確的說是變換前元素所在的與Z軸垂直的平面在Z軸上的座標位置。less

圖中演示了元素如何根據perspective屬性和z position進行縮放。ide

圖的上半部分,zd的一半。從假設的眼睛的位置看,爲了讓drawing surface上的黑色實線圓看起來好像在圖中虛線圓的位置,黑色實線圓被放大了2倍,結果就是drawing surface上的藍色圓。圖的下半部分,黑色實線圓被縮小爲原來的1/3,讓它看起來好像在drawing surface後面的虛線位置。函數

默認狀況下,觀看者的眼睛正對着的位置在drawing(surface)的中心。然而能夠經過perspective-origin屬性改變這個位置(for example, if a web page contains multiple drawings that should share a common perspective property,這句英語是理解perspective與perspective()區別的關鍵)。

圖中演示了perspective origin上移後對元素的影響。

透視變換矩陣(perspective matrix)根據下列規則計算:

  1. 以單位矩陣(identity matrix)開始
  2. 計算perspective-origin的X值和Y值並按計算值進行平移(translate)
  3. 乘以變換函數perspective()所用的矩陣,其中長度值由perspective屬性提供。矩陣如圖所示:
  4. 用perspective-origin的X值和Y值的相反數進行平移(translate)

步驟3用到的矩陣:

例子

這個例子演示了應用perspective屬性後可讓3D變換看起來更真實。

 1 <style>
 2 div {
 3   height: 150px;
 4   width: 150px;
 5 }
 6 .container {
 7   perspective: 500px;
 8   border: 1px solid black;
 9 }
10 .transformed {
11   transform: rotateY(50deg);
12 }
13 </style>
14 
15 <div class="container">
16   <div class="transformed"></div>
17 </div>

藍色div與前面例子中的藍色div進行了相同的3D變換,可是這個例子中的藍色div的渲染受到其父元素的perspective屬性值的影響。考慮到景深,perspective屬性使在Z軸上有正座標值的點在X軸和Y軸上放大了(距離觀看者更近了),在Z軸上有負座標的點在X軸和Y軸上縮小了,距離觀看者更遠了。

補充:

perspective屬性

可取值:none | <length>

該屬性能應用於可變換的元素(transformable elements)。

<length>只能爲正值,是觀看者與z=0平面的距離,使具備3D變換的元素產生透視效果(當值爲0或負值時,無透視效果,變換元素表現爲扁平化)。

值爲none時,無透視效果,元素在畫布上扁平化呈現。

perspective屬性值不爲none的元素,建立一個層疊上下文和一個包含塊(規範上說和相對定位有點相似,和transform很像)。

perspective和perspective-origin屬性的值被用於計算透視矩陣(perspective matrix)。

 

perspective-origin屬性

perspective-origin用於建立perspective屬性的起始點。事實上,該屬性設置了觀看者的眼睛在舞臺元素上的投影位置。

可取值:<percentage> | <length> | 關鍵字

默認值爲:50% 50%

第一個值表示與border box左邊界的距離,第二個值表示與border box上邊界的距離。當只指定一個值時,第二個值做爲50%處理。

<percentage>相對於舞臺元素(reference box)的border box的尺寸計算。

該屬性的語法:

1 perspective-origin: x-position;            /* one-value syntax */
2 
3 perspective-origin: x-position y-position; /* two-value syntax */
4 
5  
6 /*當 x-position 和 y-position 爲關鍵字時,如下寫法是容許的:*/
7 
8  perspective-origin: y-position x-position;

x-position

  • <percentage> 百分比,相對於元素寬度,可爲負值。
  • <length> 長度值,可爲負值。
  • left,關鍵字,0值的簡記。
  • center,關鍵字,50%的簡記。
  • right,關鍵字,100%的簡記。

y-position

  • <percentage> 百分比,相對於元素的高度,可爲負值。
  • <length> 長度值,可爲負值。
  • top,關鍵字,0值得簡記。
  • center,關鍵字,50%的簡記。
  • bottom,關鍵字,100%的簡記。

3D rendering context  3D渲染上下文

這部份內容主要講3D變換的渲染模型和transform-style屬性。

一個3D渲染上下文本質上是一個三維座標系(a common three-dimensional coordinate system),這個三維座標系由一組具備共同祖先(舞臺元素)而且進行3D變換的元素共享。

在3D渲染上下文中的元素在渲染時層次關係由他們在Z軸上的位置決定。若是3D變換使他們相互交叉,那麼在渲染時就讓他們交叉着渲染。

首先transform-style屬性值爲flat的元素建立一個3D渲染上下文,把這個元素稱爲祖先元素(舞臺元素)。

其次,若是後代元素的transform-style屬性值爲auto或preserve-3d,則該後代元素將其所處的3D渲染上下文(enclosing 3D rendering context)共享給它包含的後代元素。

再次,若是一個後代元素的transform-style屬性值爲flat,它雖然參與到包含他的父3D渲染上下文(containing 3D rendering context)中,可是同時對於它包含的後代元素,它也建立一個新的3D渲染上下文。不過,對於這個新建立的3D渲染上下文,在渲染時不是做爲一個三維空間渲染,而是做爲一個平面渲染。

注意:3D渲染上下文的概念相似於層疊上下文的概念。一個有明確z-index值的定位元素自身建立一個層疊上下文,可是他仍是參與到他所處的祖先元素建立的層疊上下文中。類似地,一個元素能爲他的後代元素建立一個3D渲染上下文,可是他自身仍是參與到他的祖先元素建立的3D渲染上下文中。就像元素在層疊上下文中按照z-index屬性決定的層次渲染同樣,元素在3D渲染上下文中按照z-depth順序渲染並且能夠互相交叉。

一些CSS屬性值使一個元素及其後代元素在渲染時做爲一個總體渲染(這些屬性及值在transform-style屬性的介紹中查看)。本質上這些CSS屬性值強制將元素的transform-style屬性的值重設爲flat,這些元素被稱爲扁平元素(flattening elements)。因此這些元素都會建立一個新的3D渲染上下文。根元素的transform-style屬性的值爲flat。

在3D渲染上下文中元素的渲染遵循如下規則(規則中提到的數字步驟參見CSS 2.1, Appendix E, Section E.2 Painting Order):

     A、步驟1和2提到的建立元素(establishing element)的background,border和其餘的盒子裝飾。

     B、按照步驟3—7的順序把建立元素的內容和後代元素中沒有進行3D變換的元素渲染到z = 0的平面內。

     C、將3D變換的元素按照各自最終的3D變換矩陣(accumulated 3D transformation matrix)渲染到他們各自所在的平面內。

     D、按照Newell’s algorithm渲染步驟B和C致使的不一樣平面之間的交叉。

     E、平面的結果集渲染到步驟A提到的background和其餘盒子裝飾的上層。共面的3D變換元素按照painting order渲染。

要注意到的是擁有負的z軸向份量(negative z-component)的變換元素會渲染到建立元素(establishing element)的內容和後代非變換元素的後面(3維空間的後面)。也就是說,3D變換的元素可能會貫穿建立元素的內容和後代非變換元素。

注意:由於3D變換元素在同一個3D渲染上下文中可能按深度排序和相互交叉,因此實際上好像是把它們當作兄弟元素進行渲染。transform-style: perserve-3d能夠被看做是將全部3D變換元素提高到了建立元素建立的同一個3D渲染上下文中,可是他們在進行3D變換時仍是按照各自最終的3D變換矩陣(accumulated 3D transformation matrix)進行變換。

例子

 1 <style>
 2 .container {
 3   background-color: rgba(0, 0, 0, 0.3);
 4   perspective: 500px;
 5 }
 6 .container > div {
 7   position: absolute;
 8   left: 0;
 9 }
10 .container > :first-child {
11   transform: rotateY(45deg);
12   background-color: orange;
13   top: 10px;
14   height: 135px;
15 }
16 .container > :last-child {
17   transform: translateZ(40px);
18   background-color: rgba(0, 0, 255, 0.6);
19   top: 50px;
20   height: 100px;
21 }
22 </style>
23 
24 <div class="container">
25   <div></div>
26   <div></div>
27 </div>

這個例子演示了在同一個3D渲染上下文中的元素能夠相互交叉。容器元素爲它自己和它的兩個子元素建立了一個3D渲染上下文。兩個子元素相互交叉,同時橙色的子元素也和容器元素的文字內容交叉。

perspective屬性能夠爲3D變換上下文中的後代變換元素提供一個共同的透視變換矩陣(perspective matrix),從而被用來確保這些3D變換元素好像處在同一個有深度的三維空間中。這個透視變換矩陣在計算最終的3D矩陣( accumulated 3D matrix computation)時被考慮在內。

默認狀況下,perspective屬性值不爲none的元素是扁平的(flattening),所以它建立一個3D渲染上下文。然而,把transform-style屬性的值設置爲preserve-3d可讓這個透視元素(perspective element)擴展包含他的3D渲染上下文的範圍至他的後代元素(provided no other grouping property values are in effect)。

例子

 1 <style>
 2 div {
 3   height: 150px;
 4   width: 150px;
 5 }
 6 .container {
 7   perspective: 500px;
 8   border: 1px solid black;
 9 }
10 .transformed {
11   transform: rotateY(50deg);
12   background-color: blue;
13 }
14 .child {
15   transform-origin: top left;
16   transform: rotateX(40deg);
17   background-color: lime;
18 }
19 </style>
20 
21 <div class="container">
22   <div class="transformed">
23     <div class="child"></div>
24   </div>
25 </div>

這個例子演示了內嵌的3D變換元素是如何渲染的。就像前面的例子同樣,藍色div的渲染受到了他的父元素的perspective屬性值的影響。檸檬色的div一樣也進行了3D變換,繞着X軸旋轉40deg(經過transform-origin屬性,X軸被固定在了頂部)。然而,檸檬的的div被渲染到了他的父元素的平面內,由於他不在他父元素所在的3D渲染上下文中。他的父元素是平的(flattening)。因此檸檬色的div僅僅是看起來短了一些,他沒有從藍色div內「翹出來」。

Transformed element hierarchies 變換元素的層次

默認狀況下,變換元素是平的(flattening),所以他們建立一個3D渲染上下文。然而,在同一個三維空間中構造層次結構是頗有用的。經過將transform-style屬性的值設爲preserve-3d可使同一三維空間內的變換元素區分各自的層次,同時也容許變換的後代元素共享同一個3D渲染上下文。在3D渲染上下文中,非3D變換的後代元素被渲染到前文步驟C中的平面內,而3D變換的元素會從這個平面內「翹出來」,翹到他們變換後所在的平面內。

例子

 1 <style>
 2 div {
 3   height: 150px;
 4   width: 150px;
 5 }
 6 .container {
 7   perspective: 500px;
 8   border: 1px solid black;
 9 }
10 .transformed {
11   transform-style: preserve-3d;
12   transform: rotateY(50deg);
13   background-color: blue;
14 }
15 .child {
16   transform-origin: top left;
17   transform: rotateX(40deg);
18   background-color: lime;
19 }
20 </style>

這個例子中藍色div的transform-style屬性的值被設爲了preserve-3d,其他的代碼和前一個例子徹底相同。如今,藍色的div將容器元素的3D渲染上下文的範圍擴展了,藍色div和檸檬色的div共享同一個三維空間。同時受到容器元素perspective屬性的影響,檸檬色的div從他的父元素的平面內翹出來了。

transform-style屬性

該屬性能應用於可變換的元素(transformable elements)。

該屬性要在父元素上設置,對該父元素的子元素(或者說後代元素)起做用。

transform-style的可取值爲:auto   |   flat | preserve-3d

默認值爲 auto,不可繼承。

當transform-style的值爲「flat」時,元素建立一個層疊上下文(stacking context)和一個3D渲染上下文(3D rendering context)。

transform-style屬性值爲「auto」的元素在計算3D渲染上下文時會被忽略。

transform-style屬性值爲「preserve-3d」的元素會擴大其所處的3D渲染上下文的範圍,即便transform 或 preserve屬性的值會致使扁平化。同時,transform-style屬性值爲「preserve-3d」的元素會建立一個層疊上下文和一個包含塊。

Grouping property values

如下CSS屬性值會致使後代元素(descendant elements)扁平化顯示,也就是說強制父元素transform-style屬性的值轉變爲「flat」:

如下CSS屬性值會使transform-style的默認值重設爲flat:

Accumulated 3D Transformation Matrix Computation

在3D渲染上下文中,用來渲染一個元素的最終變換值是經過累加accumulated 3D transformation matrix獲得的。累加規則以下:

  1. Let transform be the identity matrix.

  2. Let current element be the transformed element.

  3. Let ancestor block be the element that establishes the transformed element’s containing block.

  4. While current element is not the element that establishes the transformed element’s 3D rendering context:

    1. If current element has a value for transform which is not none, pre-multiply current element’s transformation matrix with the transform.

    2. Compute a translation matrix which represents the offset of current element from its ancestor block, and pre-multiply that matrix into the transform.

    3. If ancestor block has a value for perspective which is not none, pre-multiply the ancestor block’s perspective matrix into the transform.

    4. Let ancestor block be the element that establishes the current element’s containing block.

    5. Let current element be the ancestor block.

注意:accumulated 3D transformation matrix把視覺格式化模型(visual formatting model)在變換元素上產生的偏移量計算在內,並且也把建立3D渲染上下文的元素(舞臺元素)與變換元素之間樹形圖上的元素考慮在內。

Backface Visibility 背面可見性

利用三維變換,使看到變換元素的背面成爲可能。在背面可見的狀況下,不論是哪一面,3D變換元素都顯示一樣的內容,背面內容是前面內容的鏡像(就好像元素被投影到一面鏡子上)。默認狀況下,當元素的背面朝向觀看者時,觀看者能夠看到這個背面的內容。事實上,當元素的背面朝向觀看者時,開發者能夠經過backface-visibility屬性,讓該元素的內容不可見。

若是一個動畫元素的backface-visibility屬性的值爲hidden,那麼他的內容是交替可見的。只有當他的前面朝向觀看者時,他的內容纔是可見的。

例子

這個例子演示瞭如何製做一張可經過點擊進行翻轉的卡片。爲了不翻轉時出現扁平化,#card元素的transform-style: preserve-3d屬性是必須的。

 

 1 <style>
 2 .body { perspective: 500px; }
 3 #card {
 4   position: relative;
 5   height: 300px; width: 200px;
 6   transition: transform 1s;
 7   transform-style: preserve-3d;
 8 }
 9 #card.flipped {
10   transform: rotateY(180deg);
11 }
12 .face {
13   position: absolute;
14   top: 0; left: 0;
15   width: 100%; height: 100%;
16   background-color: silver;
17   border-radius: 40px;
18   backface-visibility: hidden;
19 }
20 .back {
21   transform: rotateY(180deg);
22 }
23 </style>
24 <div id="card" onclick="this.classList.toggle('flipped')">
25   <div class="front face">Front</div>
26   <div class="back face">Back</div>
27 </div>

backface-visibility屬性

可取值:visible | hidden

默認值:visible

該屬性對2D變換無效。

visible 表示背面可見,容許顯示正面的鏡像。

hidden 表示背面不可見。

The visibility of an element with backface-visibility: hidden is determined as follows:

  1. Compute the element’s accumulated 3D transformation matrix.

  2. If the component of the matrix in row 3, column 3 is negative, then the element should be hidden. Otherwise it is visible.

3D Transform Functions

MDN上講的比較詳細,不過是英文。地址:transform-function

元素變換時所用的座標系是局部座標系

matrix3d()

該函數接受16個參數,這16個參數是一個4*4的矩陣。具體看規範Mathematical Description of Transform Functions

translate3d()

該函數接受3個參數,前兩個參數能夠爲<length>,也能夠爲<percentage>,第三個參數只能爲<length>。百分數相對於變換元素的border box的尺寸計算。

三個參數組成一個三維向量,三個值分別表示這個向量在相應座標軸上的座標,變換元素根據這個向量進行平移。

translateX()和translateY()在2D變換中已經介紹過了,這裏只介紹translateZ()。

translateZ()

該函數只接受一個參數,使變換元素沿着Z軸移動指定的長度,至關於translate3d(0,0,tz),並且只能用在3D變換中。

scale3d()

該函數接受3個<number>參數,分別表明變換元素在X軸,Y軸和Z軸上的縮放比例。若是對應某一座標軸上的參數值在(-1,1)範圍內,則元素在該座標軸方向上縮小,超出上述範圍,則元素在該座標軸方向上放大。若是等於1或-1,元素在該座標軸上的尺寸不變。另外,負號表示對稱變換。

scaleZ()

該函數只接受一個參數,至關於scale3d(1,1,sz)。

注意:單獨使用3D的縮放變換,除了能在X軸和Y軸上看到效果,Z軸上是看不到效果的。

rotate3d()

該函數可使元素繞着座標軸進行3D旋轉變換,正值表示順時針旋轉,負值表示逆時針旋轉。

在3D空間中,旋轉有三個自由度。旋轉軸能夠經過一個通過座標原點(transform-origin指定)的三維向量 [x,y,z] 表示。若是這個向量不是標準化的向量(單位向量),瀏覽器會在內部自動將其轉換爲標準化的向量。若是這個向量不能被標準化(好比[0,0,0]),那麼元素本次的旋轉變換將無效,而不是將整個transform屬性無效。

注意:與2D的旋轉變換相比,交換同一元素的不一樣的3D旋轉變換的次序獲得的結果是徹底不一樣的,因此對所應用的3D旋轉變換的順序要引發重視。

語法:rotate3d(x, y, z, a)

x  表示旋轉軸在x軸上的座標

y  表示旋轉軸在y軸上的座標

z  表示旋轉軸在z軸上的座標

a  是一個<angle>值,表示旋轉的角度,正值表示順時針旋轉;負值表示逆時針旋轉。

rotateX()

只接受一個<angle>參數,至關於rotate3D(1, 0, 0, a)

rotateY()

只接受一個<angle>參數,至關於rotate3D(0, 1, 0, a)

rotateZ()

只接受一個<angle>參數,至關於rotate3D(0, 0, 1, a)

perspective()

該函數接受一個<length>參數,本質是指定一個透視投影矩陣(perspective projection matrix),使元素進行透視投影變換。這個矩陣根據座標點的z座標對x座標和y座標進行縮放:放大z座標爲正的點,使該點遠離原點;縮小z座標爲負的點,使該點靠近原點;z=0平面上的點不變。傳入該函數的參數表明的是觀看者的眼睛(假設的)與z=0平面之間的距離。值越小,獲得的視錐體越扁平,透視效果越明顯。好比,傳入參數爲1000px時,結果是一個適中的透視縮短效果;傳入參數爲200px時,結果是一個極端的透視縮短效果。傳入的值必須大於0,不然無效。

總結

要實現3D變換,要用到下面幾個屬性:

屬性

描述

CSS

transform

向元素應用 2D 或 3D 轉換。

3

transform-origin

設置變換基點(局部座標系原點)的位置。

3

transform-style

規定被嵌套元素如何在 3D 空間中顯示。

3

perspective

規定 3D 元素的透視效果。

3

perspective-origin

規定觀看者眼睛的投影位置。

3

backface-visibility

定義元素內容在不面對屏幕時是否可見。

3

 

 

參考資料和相關文章:

一、transform-function

二、CSS3 transform

三、爲什麼使用了 css3 translate3d 會致使顯示模糊?

四、CSS3 3D Transform

五、使用 CSS 轉換爲你的網頁帶來活力讓你的網頁栩栩如生

六、CSS Transforms Module Level 1

七、深刻探索透視投影變換

相關文章
相關標籤/搜索