首先聲明一點,transform屬性不爲none的元素是它的定位子元素(絕對定位和固定定位)的包含塊,並且對內建立一個新的層疊上下文。css
注意:能夠經過 transform-box 屬性指定元素的那個盒子發生了變換,該屬性的默認值是「border-box」,查MDN只有Firefox支持該屬性(我試的沒效果)。html
CSS 3 中2D轉換的實現用到兩個屬性:前端
屬性 | 描述 | CSS |
---|---|---|
transform | 向元素應用 2D 或 3D 轉換。 | 3 |
transform-origin | 指定變換的基點的位置。 | 3 |
該屬性其實是指定局部座標系的原點位置。css3
語法:web
transform-origin: [ left | center | right | top | bottom | <percentage> | <length> ]
|
[ left | center | right | <percentage> | <length> ]
[ top | center | bottom | <percentage> | <length> ] <length>?
|
[ center | [ left | right ] ] && [ center | [ top | bottom ] ] <length>?
默認值爲: 50% 50% 0;數組
不可繼承。wordpress
值的計算都是以元素的border box爲基準的,transform-origin的默認值把局部座標系的原點移到了元素的中心。函數
注意:關於轉換元素建立的局部座標系,參見規範中的解釋:local coordinate system佈局
若是隻指定了一個值,那麼第二個值做爲 "center" 處理;若是隻指定了一個或兩個值,第三個值做爲 「0px」處理。spa
若是指定了兩個或更多的值(三個)並且沒有使用關鍵字類型的值,或者只使用了關鍵字「center」,那麼第一個值表明距離border box左邊界的距離,第二個值表明距離border box上邊界的距離,第三個值表明在 z 軸方向上的位置(或位移),並且必須爲長度值<length>。
關鍵字 | 解釋 |
top | 至關於垂直方向上的 0% |
right | 至關於水平方向上的 100% |
bottom | 至關於垂直方向上的 100% |
left | 至關於水平方向上的 0% |
center | 在垂直方向上至關於50% 或者在水平方向上至關於50% |
MDN上對於可取值舉的例子:
1 /* 單值語法 */ 2 transform-origin: 2px; 3 transform-origin: bottom; 4 5 /* 雙值語法 */ 6 /* 用兩個數字值先水平後垂直,用一個數值一關鍵字或兩關鍵字不強求順序 */ 7 transform-origin: 3cm 2px; /* x-offset y-offset */ 8 transform-origin: 2px left; /* y-offset x-offset-keyword */ 9 transform-origin: left 2px; /* x-offset-keyword y-offset */ 10 transform-origin: right top; /* x-offset-keyword y-offset-keyword */ 11 transform-origin: top right; /* y-offset-keyword x-offset-keyword */ 12 13 /* 三值語法 */ 14 transform-origin: 2px 30% 10px; /* x-offset y-offset z-offset */ 15 transform-origin: 2px left 10px; /* y-offset x-offset-keyword z-offset */ 16 transform-origin: left 5px -3px; /* x-offset-keyword y-offset z-offset */ 17 transform-origin: right bottom 2cm; /* x-offset-keyword y-offset-keyword z-offset */ 18 transform-origin: bottom right 2cm; /* y-offset-keyword x-offset-keyword z-offset */
注意:
例子:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <style> 5 .div1 6 { 7 position: relative; 8 height: 200px; 9 width: 200px; 10 margin: 100px; 11 padding:10px; 12 border: 1px solid black; 13 overflow: auto; 14 } 15 16 .div2 17 { 18 padding:50px; 19 border: 1px solid black; 20 background-color: red; 21 transform: translate(100px) rotate(60deg) translate(100px,100px); 22 } 23 </style> 24 </head> 25 <body> 26 <div class="div1"> 27 <div class="div2">HELLO 28 </div> 29 </div> 30 </body> 31 </html>)
效果:
transform屬性用於2D轉換的方法函數主要有如下幾個。
轉換方法 | 轉換方式 |
translate() | 平移 |
scale() | 縮放 |
rotate() | 旋轉 |
skew() | 傾斜 |
matrix() | 矩陣變換 |
translate()函數指定元素的平移轉換。他可接受兩個參數,第一個參數表示沿 x 軸的平移量,第二個值表示沿 y 軸的平移量。若是隻指定一個值,第二個值做爲 0 處理。
另外還有隻向一個方向平移的函數:
示例:
1 <!DOCTYPE html> 2 <html> 3 <head> 4 <style> 5 #div3{ 6 background-color: pink; 7 height: 250px; 8 width: 250px; 9 } 10 #div4{ 11 height: 100px; 12 width: 100px; 13 background-color: gray; 14 transform: translate(100px,100px); 15 } 16 #div5{ 17 height: 50px; 18 width: 50px; 19 background-color: yellow; 20 } 21 </style> 22 </head> 23 24 <body> 25 <div id="div3"> 26 <div id="div4" > 27 <div id="div5"></div> 28 </div> 29 </div> 30 </body> 31 </html>
效果:
從圖中能夠看出,做爲子元素的黃色 div 也跟着平移了。
scale() 函數能夠接受兩個數字參數,表示縮放倍數。
第一個參數表示沿 x 軸的縮放,第二個值表示沿 y 軸縮放。小於 1,縮小;等於 1,大小不變;大於 1,放大。
若是隻指定一個值,那麼第二個值會被認爲等於第一個值。
一樣也有隻沿一個方向縮放的函數:
示例:
1 <style> 2 #div3{ 3 background-color: pink; 4 height: 200px; 5 width: 200px; 6 } 7 #div4{ 8 height: 100px; 9 width: 100px; 10 background-color: gray; 11 transform: translate(50px,50px) scale(2); 12 } 13 #div5{ 14 height: 50px; 15 width: 50px; 16 background-color: yellow; 17 } 18 </style> 19 20 <body> 21 <div id="div3"> 22 <div id="div4" > 23 <div id="div5"></div> 24 </div> 25 </div> 26 </body>
效果:
沿 x 軸和沿 y 軸的縮放距離是如何肯定的呢?
具體要看基點在哪裏,以上面的示例爲例說明。
示例中粉色 div 是邊長200px的正方形,灰色 div 是邊長爲100px的正方形,黃色 div 是邊長50px的正方形,發生變換的是灰色 div。
灰色 div 變換的基點默認狀況下在他的中心點。
以變換基點做局部座標系,座標軸的方向:x 軸向右爲正;y 軸向下爲正。此時在局部座標系中,灰色 div 的邊長被座標原點均分到座標軸的正負軸上,即正軸上的長度與負軸上的長度的比例爲 1:1。當元素縮放變換時,就用局部座標系中正負半軸上的部分邊長分別乘以對應方向上的縮放倍數,用獲得的值減去原來分佈在半軸上的邊長就獲得元素應該在改半軸上擴展的距離。
示例中,灰色 div 分佈在局部座標系 x 軸正半軸上的邊長爲50px,那麼50*2 = 100,100 - 50 = 50,因此灰色 div 沿局部座標系 x 軸的正軸方向向外擴展50px,分佈在其餘半軸上的邊長同理。最終結果就是灰色 div 剛好徹底覆蓋住粉色 div。
下面再舉一個例子。
圖中粉色 div 不考慮黑色邊框時是邊長爲300px的正方形,灰色 div 是邊長100px的正方形。若是灰色 div 的初始位置如圖中所示,距離粉色 div 左側和頂部分別爲50px,那麼灰色 div 僅僅經過縮放變換(須要改變變換基點的位置),要放大幾倍能恰好覆蓋粉色 div(不覆蓋邊框)?
這個問題能夠經過前文介紹的縮放距離的計算方法計算出來,個人計算結果:
代碼:
1 <style> 2 #div3{ 3 position:relative; 4 background-color: pink; 5 height: 300px; 6 width: 300px; 7 border: 1px solid black; 8 } 9 #div4{ 10 position: absolute; 11 top: 50px; 12 left: 50px; 13 height: 100px; 14 width: 100px; 15 background-color: gray; 16 transform-origin: 25px 25px; 17 transform: scale(3); 18 } 19 #div5{ 20 height: 50px; 21 width: 50px; 22 background-color: yellow; 23 } 24 </style> 25 26 <body> 27 <div id="div3"> 28 <div id="div4" > 29 <div id="div5"></div> 30 </div> 31 </div> 32 </body>
效果:
另外,scale()函數還能夠接受負值。
好比:
若是是scale(-1, 1),則轉換後元素的位置與元素經scale(1, 1)變換後的位置關於局部座標系的 y 軸的對稱。
若是是scale(1, -1),則轉換後元素的位置與元素經scale(1, 1)變換後的位置關於局部座標系的 x 軸的對稱。
若是是scale(-1, -1),則轉換後元素的位置與元素經scale(1, 1)變換後的位置關於局部座標系的原點(變換基點)中心對稱。
示例:
代碼仍是前一例的代碼。
scale(-3)變換與scale(3)變換的位置關於變換基點(25px, 25px)中心對稱。
rotate()函數經過指定的角度參數讓元素進行2D旋轉變換。
接受一個角度值,用來指定旋轉的幅度。
若是這個值爲正值,元素順時針旋轉;若是這個值爲負值,元素逆時針旋轉。
rotate()變換的元素繞着什麼旋轉呢?
實際上是繞着局部座標系(原點在變換基點)的 z 軸旋轉。
示例:
1 <style> 2 #div3{ 3 position:relative; 4 background-color: pink; 5 height: 300px; 6 width: 300px; 7 border: 1px solid black; 8 margin: auto; 9 } 10 #div4{ 11 position: absolute; 12 top: 50px; 13 left: 50px; 14 height: 100px; 15 width: 100px; 16 background-color: gray; 17 transform-origin: 25px 25px; 18 transform: rotate(-90deg); 19 } 20 #div5{ 21 height: 50px; 22 width: 50px; 23 background-color: yellow; 24 } 25 </style> 26 27 <body> 28 <div id="div3"> 29 <div id="div4" > 30 <div id="div5"></div> 31 </div> 32 </div> 33 </body>
效果:
經過skew()函數,元素能夠實現傾斜變換。
該函數能夠接受兩個參數(能夠爲負值),第一個參數表示元素的border box 的垂直邊與參照座標系 y 軸的夾角,第二個參數表示元素的border box 的水平邊與參照座標系 x 軸的夾角。
若是隻指定了一個值,第二個值做爲 0 處理。
另外也有隻能指定一個夾角的函數:
示例:
1 <style> 2 3 /***********skew************/ 4 #div6{ 5 position:relative; 6 height: 300px; 7 width: 300px; 8 border: 1px solid black; 9 margin: auto; 10 } 11 #div7{ 12 position:absolute; 13 top:75px; 14 left:75px; 15 height: 150px; 16 width: 150px; 17 background-color: #5555FF; 18 } 19 #div8{ 20 position:absolute; 21 top:75px; 22 left:75px; 23 height: 150px; 24 width: 150px; 25 opacity: 0.7; 26 background-color: #66FF66; 27 } 28 </style> 29 30 <body> 31 <!--skew--> 32 <div id="div6"> 33 <div id="div7"></div> 34 <div id="div8"></div> 35 </div> 36 </body>
上面的代碼的效果以下:
給 id="div8" 的元素添加如下CSS代碼:
transform: skew(60deg);
或者
transform: skew(-120deg);
能夠獲得下圖所示效果:
圖中標出了局部座標系及夾角。
矩陣變換。
利用矩陣變換能夠實現以上介紹的全部2D變換。也就是說,matrix()函數是以上幾個函數的並集。
該函數能夠接受6個參數,分別用a、b、c、d、e、f指代:
matrix(a, b, c, d, e, f);
這6個參數組成下面這個矩陣:
這就是 transform 的2D變換矩陣。
矩陣變換的原理:
x、y表示變換前元素上某一點在局部座標系中的橫縱座標。
令
x' = ax + cy + e
y' = bx + dy + f
則 x'、y' 表示變換後元素上這一點在局部座標系中的橫縱座標。
根據 x' 和 y' 的計算公式,只要給a、b、c、d、e、f指定不一樣的值就能夠實現上述幾種變換。
平移變換就是給原座標分別加上咱們指定的值。
舉例,若是變換前元素中有一個點的座標爲(10px, 20px),通過 translate(20px, 5px) 的平移變換,則變換後該點的橫座標變爲
10px + 20px = 30px
縱座標變爲
20px + 5px = 25px
即點(10px, 20px)平移到了點 (30px, 25px)。
根據 x' 的計算公式,讓 a = 1,c = 0,e = 20,則 x' = 30;
根據 y' 的計算公式,讓 b = 0,d = 1,f = 5,則 y' = 25;
因此 matrix(1, 0, 0, 1, 20, 5) 能夠實現平移變換 translate(20px, 5px)。
其實,不論是什麼樣的平移變換,只要讓 a = 1, b = 0,c = 0,d = 1,那麼 e 就至關於translate()的第一個參數,f 就至關於translate()的第二個參數。
縮放變換變換前的橫縱座標分別乘以指定的縮放倍數,從而獲得變換後的橫縱座標。
舉例,用matrix()實現scale(2,3)。
x' = 2x
y' = 3y
只要令 a = 2,c = 0,e = 0;b = 0,d = 3,f = 0 便可。即:
matrix(2, 0, 0, 3, 0, 0);
其實,不論是什麼樣的縮放變換,只要讓 b = 0,c = 0,e = 0,f = 0,那麼 a 就至關於scale()的第一個參數,d 就至關於scale()的第二個參數。
若是有旋轉變換rotate(θ),則 x' 、y' 的計算公式就變爲:
x’ = x*cosθ - y*sinθ + 0 = x*cosθ - y*sinθ
y’ = x*sinθ + y*cosθ + 0 = x*sinθ + y*cosθ
也就是說
a = cosθ,c = - sinθ , e = 0
b = sinθ,d = cosθ,f = 0
即
matrix(cosθ, sinθ, -sinθ, cosθ, 0, 0);
若是有傾斜變換scale(θx, θy),則 x' 、y' 的計算公式就變爲:
x’ = x + y*tanθx + 0 = x + y*tanθx
y’ = x*tanθy + y + 0 = x*tanθy + y
也就是說
a = 1,c = tanθx , e = 0
b = tanθy,d = 1,f = 0
即
matrix(1, tanθy, tanθx, 1, 0, 0);
這裏說的簡單鏡像變換是指變換前的元素和變換後的元素關於通過局部座標系原點的直線 y = kx 對稱。
盜一張張大神的圖:
關於參數的推到直接看張大神的文章,這裏直接貼結果。
x' = (1-k*k) / (k*k+1) *x + 2k / (k*k+1) *y;
y' = 2k / (k*k+1) *x + (k*k-1) / (k*k+1) *y;
因此
a = (1-k*k) / (k*k+1)
b = 2k/(k*k+1)
c = 2k/(k*k+1)
d = (k*k-1)/(k*k+1)
e = 0
f = 0
(完)
參考資料
一、官方文檔