CSS門檻低,無(wú)需程序基礎(chǔ)或數(shù)學(xué)邏輯能力,也能做出點(diǎn)自我感覺(jué)不錯(cuò)的東西。然而,你自己也應(yīng)該清楚的,一般你能輕松學(xué)到的東西,別人也可以。因此,如果你想擠進(jìn)那20%的行列,就要學(xué)到一般人學(xué)不到的深度,學(xué)到一般人學(xué)不了的東西。自然,是需要更多額外的努力的。如果每次你都比別人努力一點(diǎn)點(diǎn),何愁不比他人高出幾等。人年輕的時(shí)候,貴在堅(jiān)持!CSS中也是有復(fù)雜的高檔貨,transform中的矩陣matrix就是其中典型一個(gè)。
? Transform 是CSS極為關(guān)鍵且復(fù)雜的一個(gè)屬性,功能豐富而且強(qiáng)大,能方便解決很多平常難以處理的問(wèn)題,但她本身有些學(xué)習(xí)難度,如果你對(duì)頁(yè)面效果愛(ài)的深沉,也請(qǐng)你對(duì)她愛(ài)的深沉。

# Transform的值大類
? transform 本質(zhì)上來(lái)說(shuō)是一系列的變形函數(shù),主要有以下值:
- none - 不進(jìn)行轉(zhuǎn)換,常用作覆蓋別的值使用
- translate(x,y) - 2d位移;translate3d(x,y,z) - 3d位移; transformX/Y/Z(n) - 單向位移
- scale(x,y) - 2d縮放; scale3d(x,y,z) - 3d縮放; scaleX/Y(n) - 單向縮放
- rotate(angle) - 2d旋轉(zhuǎn); rotate3d(x,y,z,angle) - 3d旋轉(zhuǎn);rotateX/Y/Z(angle) - 單向旋轉(zhuǎn)
- skew(x-angle,y-angle) - 傾斜變換; skewX/Y(angle) - 單向傾斜變換
- matrix[3d] - 矩陣
-
perspective(n) - 視距(值)
?
# Transform的前置屬性
- transform-origin - 變換原點(diǎn)
- transform-style - 變換類型
- perspective - 3d透視視圖的視距(屬性)
- perspective-origin - 視距的基點(diǎn)
- backface-visibility - 是否可以看見(jiàn)舞臺(tái)背面
? 看到這里是不是已經(jīng)快頭暈了?是否開(kāi)始懷疑你以前知道的是假的 transform ?如果你看到你不熟悉或不會(huì)的,沒(méi)關(guān)系,好好看,本文會(huì)給你細(xì)細(xì)道來(lái)。
?
# 位移 - transform: translate(x,y)
? trnaslate2d位移系列,主要有:translate(x[,y]), translateX(x), translateY(y), translateZ(z), translate3d(x,y,z)
? translate(x[,y]) 當(dāng)參數(shù)設(shè)置為正數(shù)時(shí)表示正向移動(dòng),負(fù)數(shù)為反向移動(dòng),類似于 position:relative + margin;這里注意,y值的設(shè)置是可以省略的,與margin、padding 省略值后表示兩者值一致不同的是,如果省略了y,則表示y的值為0。例:translate(50px) 同 translate(50px,0) 表示沿x軸向右移動(dòng)50個(gè)像素,y軸不變。
? 如果要使用 translate(x,y) ,最好不要省略參數(shù),如果只需要偏移一個(gè)方向,建議使用 translateX() 或 translateY() ;關(guān)于 translate(x,y),我有一個(gè)很經(jīng)典的案例分享給大家:按鈕實(shí)現(xiàn)上下左右絕對(duì)居中(不受文字字號(hào)影響)
<div>
<font>這里是文案</font>
</div>
div {
position: relative;
}
font {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}

? translate3d位移主要有:translate3d(x,y,z), translateZ(z)
? 先說(shuō)簡(jiǎn)單的,translateZ(z) 是指在z軸方向上的位移效果,直白點(diǎn)說(shuō)就是圖像距離看官的距離關(guān)系,距離越近,圖像就越大;舉個(gè)例子如 看遠(yuǎn)處的山比看近處的手指還小。
? 到這里必須要提前提到另一個(gè)屬性:視距 perspective - 表示看官眼睛的位置;當(dāng) translate 值超過(guò)視距時(shí),圖像就消失了,就好比圖像移動(dòng)到看官眼睛后面一樣,這個(gè)大家應(yīng)該都能理解。我們用代碼來(lái)說(shuō)話(省去不相關(guān)屬性):
<div>
<p></p>
</div>
div {
width: 100px;
height: 100px;
perspective: 100px;
}
p {
width: 30px;
height: 30px;
border-radius: 50%;
transform: translateZ(75px);
}
【注意坑】要使用translateZ,必須在父元素上設(shè)置perspective

案例中我們可以看出,我們只設(shè)置了
30px的寬高,但因?yàn)樵O(shè)置了圖像向前移動(dòng) (75/100)% , 因此,圖像變大變近了。大家應(yīng)該能感覺(jué)的出來(lái),綠圓在白色成的前面。(!好吧,我問(wèn)了身邊的女士,她說(shuō)沒(méi)感覺(jué))
? 會(huì)了translareZ(z) 之后,translate3d(x,y,z)` 也就簡(jiǎn)單了,無(wú)非就是在做Z位移的同時(shí)做了x,y的位移;把剛才的例子稍作修改后直接上代碼:
transform: translate3d(5px,5px,75px);

【一個(gè)引申】看完也許你會(huì)問(wèn),如果
translate(x,y) 和 position:relative 類似,為什么不用后者呢?簡(jiǎn)單好記。說(shuō)的也不算全錯(cuò),畢竟有使用場(chǎng)景。但,前者有幾點(diǎn)后者無(wú)法達(dá)到的優(yōu)勢(shì),而且很關(guān)鍵。
- 如果是動(dòng)畫效果,
translate能達(dá)到比1px更小的過(guò)渡效果,而后者卻不行,這就影響了用戶體驗(yàn); -
translate的動(dòng)畫效果能啟用電腦GPU加速,分離圖層,大大減少頁(yè)面重繪模塊,節(jié)省資源。 -
position的可拓展性不如translate等。
?
# 縮放 - transform: scale(x,y)
? scale2d縮放系列,主要有:scale(x,y), scaleX(x), scaleY(y)
? scale(x[,y]) 允許省略y,當(dāng)省略y時(shí)表示x,y等值縮放。如果只想縮放x或y軸,可以使用 scaleX(x), scaleY(y) 。既然為縮放,傳遞的參數(shù)肯定為縮放比例,也就是說(shuō),約定 1 為大小不變,0.01~0.99 表示縮小,>1 表示放大。
? 例:scale(0.5) 等同于 scale(0.5, 0.5); scaleX(0.5) 等同于 scale(0.5, 1)
? 還有一個(gè)特例,如果我們設(shè)置縮放比例為負(fù)數(shù)會(huì)怎么樣?一起來(lái)看一下效果:
transform: scale(-1);

transform: scale(-1.5);

所以說(shuō),設(shè)置負(fù)數(shù),可以使圖像翻轉(zhuǎn),縮放規(guī)則與正數(shù)一致。
? scale3d縮放系列,有:scale3d(x,y,z) , scaleZ(z)
? 所謂3d縮放,就是在z軸上也有縮放效果,但只有在z軸上有分內(nèi)容時(shí)才能生效(其實(shí)x,y軸也一樣,只是x,y軸上的直觀容易理解些)
? scale3d的第三個(gè)參數(shù),比位移的第三個(gè)參數(shù)可難以理解多了。拋開(kāi)其他因素,我們先來(lái)研究scaleZ(z)。因?yàn)樗且粋€(gè)3d變形效果,因此同 translateZ(z) 一致,我們需要為其創(chuàng)建一個(gè)3d環(huán)境,這里把translateZ一起加進(jìn)來(lái)對(duì)比討論。
<div class="perspective">Translated</div>
<div>Normal</div>
<div class="scaled">Scaled</div>
div {
display: inline-block;
width: 80px;
height: 80px;
background-color: skyblue;
}
.perspective {
/* Includes a perspective to create a 3D space */
transform: perspective(400px) translateZ(-100px);
background-color: cornsilk;
}
.scaled {
/* Includes a perspective to create a 3D space */
transform: perspective(400px) scaleZ(2);
background-color: pink;
}

? 你應(yīng)該和我一開(kāi)始感覺(jué)一樣,在想,為什么設(shè)置了
scaleZ(2) 但粉色塊一直不動(dòng)呢?試試你會(huì)發(fā)現(xiàn),參數(shù)設(shè)置成100它都不動(dòng),為什么呢?因?yàn)榇藭r(shí)他和屏幕處在 平行狀態(tài),z軸方向上的分內(nèi)容為0,因此,參數(shù)設(shè)置多少都不變。那如果我們把粉色塊旋轉(zhuǎn)一下使得z軸上有分內(nèi)容,來(lái)對(duì)比一下效果:
.scaled {
/* Includes a perspective to create a 3D space */
transform: perspective(100px) scaleZ(1) rotateY(-20deg);
background-color: pink;
}

如果此時(shí)將scale參數(shù)設(shè)置為2,結(jié)果如下:

可以看到z軸上的效果明顯增強(qiáng)了,或許你會(huì)覺(jué)得,這不是旋轉(zhuǎn)的角度增大了么,其實(shí)不然!不信來(lái)看看
rotateY(-40deg) 的效果
<div class="scaled">Scaled</div>
<div class="rotated">rotated</div>
.scaled {
/* Includes a perspective to create a 3D space */
transform: perspective(100px) scaleZ(2) rotateY(-20deg);
background-color: pink;
}
.rotated {
/* Includes a perspective to create a 3D space */
transform: perspective(100px) scaleZ(1) rotateY(-40deg);
background-color: pink;
}

? 大家應(yīng)該也能看出區(qū)別來(lái),
rotate的旋轉(zhuǎn)會(huì)使圖像的寬度發(fā)生變化,如果旋轉(zhuǎn)90°,處在與屏幕垂直狀態(tài),看官就看不到這個(gè)圖形了,而 scaleZ() 只會(huì)修改圖形在z軸上的拉伸,并不會(huì)改變圖形的寬度。?
# 旋轉(zhuǎn) - transfrom: rotate(angle)
? rotate2d旋轉(zhuǎn)系列,有: rotate(angle)
【注】與前兩個(gè)不同,rotateX, rotateY 同 rotateZ都為rotate3d旋轉(zhuǎn)
? 參數(shù) angle 表示旋轉(zhuǎn)角度,單位為 deg ;當(dāng)角度為正數(shù)時(shí)表示順時(shí)針旋轉(zhuǎn),為負(fù)數(shù)時(shí)表示逆時(shí)針旋轉(zhuǎn),來(lái)看一個(gè)例子:
<div>Nomal</div>
<div class="rotated">Rotated</div>
<div class="rotated2">Rotated2</div>
div {
display: inline-block;
width: 80px;
height: 50px;
}
.rotated {
transform: rotate(30deg);
}
.rotated2 {
transform: rotate(-30deg);
}

? rotate3d旋轉(zhuǎn)系列,有:rotateX(angle), rotateY(angle), rotateZ(angle), rotate3d(x, y, z, angle)
? 要解釋3d旋轉(zhuǎn),必須要先弄清楚旋轉(zhuǎn)軸。關(guān)于旋轉(zhuǎn)軸,如下:

? 其中,網(wǎng)布就是我們的屏幕,x軸沿屏幕平行的水平方向,y軸沿屏幕平行的垂直方向,z軸沿與屏幕垂直方向。
?
rotateX(angle)表示沿著x軸旋轉(zhuǎn),經(jīng)過(guò)旋轉(zhuǎn)后,內(nèi)容以傾斜形式呈現(xiàn),所以,高度會(huì)減少;rotateY(angle) 沿著y軸旋轉(zhuǎn),所以寬度會(huì)減少,rotateZ(angle) 有些奇怪,與我們平時(shí)所想的不太一致,他是沿著屏幕做傾斜旋轉(zhuǎn)。
.rotateX {
transform: rotateX(45deg);
}
.rotateY {
transform: rotateY(45deg);
}
.rotateZ {
transform: rotateZ(30deg);
}

?或許你不明白,為什么我旋轉(zhuǎn)了之后沒(méi)有出現(xiàn)矩形效果呢?更近的地方不應(yīng)該看起來(lái)更大嗎?非常好的問(wèn)題,說(shuō)明你思考了,這里我們漏了一個(gè)很重要的因素,設(shè)定3D環(huán)境
perspective;在沒(méi)有設(shè)定視距條件下,會(huì)被默認(rèn)為視距無(wú)窮遠(yuǎn),因此旋轉(zhuǎn)得到的微弱的梯形效果也就忽略了。 加上視距得到如下
.rotateX {
transform: perspective(100px) rotateX(45deg);
}
.rotateY {
transform: perspective(100px) rotateY(45deg);
}
.rotateZ {
transform: perspective(100px) rotateZ(30deg);
}

? 這才是正確的效果。
? 再來(lái)學(xué)習(xí)
rotate3d(x,y,z,angle);看起來(lái)很難,其實(shí)很簡(jiǎn)單。前三個(gè)參數(shù)取值為 -1,0,1 分別表示反向旋轉(zhuǎn),不旋轉(zhuǎn),正向旋轉(zhuǎn);第四個(gè)參數(shù)表示旋轉(zhuǎn)角度。
.rotate3d {
background: lightgreen;
transform: perspective(100px) rotate3d(1,0,-1,30deg);
}

?
# 傾斜 - transform: skew(x-angle, y-angle)
? skew傾斜系列
? skew傾斜允許使用一個(gè)值,當(dāng)使用一個(gè)值時(shí)表示 y-angle 為0;傾斜有一個(gè)難點(diǎn)就是它的直角坐標(biāo)系,關(guān)于官方的一大堆解釋我們不做深入研究,為方便理解,如下(圖侵刪)

? 也就是說(shuō),x軸的方向是豎直方向的,y軸的方向是水平方向的。以逆時(shí)針為正角度方向
.skewed {
transform: skewX(45deg);
}

.skewed {
transform: skewY(20deg);
}

【特別注意】原點(diǎn)在圖形的中心位置,而不是在任何一個(gè)角上。直角坐標(biāo)系的第四象限(盒子所在位置)是正值所在區(qū)域。所以,x軸正方向是逆時(shí)針?lè)较?,y軸的正方向是順時(shí)針?lè)较?/strong>
.skewed {
transform: skewX(30deg,10deg);
}

?
# 矩陣 - matrix
? 矩陣是什么?別的一看就懂,但這個(gè)是什么?看不懂???其實(shí),矩陣就是這東西:

? 還是不懂?簡(jiǎn)單來(lái)說(shuō),矩陣就是使圖形發(fā)生變化(傾斜,縮放,旋轉(zhuǎn),平移)的原理所在。接下來(lái)的內(nèi)容是頁(yè)面狗逆襲的途徑之一,需要點(diǎn)數(shù)學(xué)基礎(chǔ):
? 在線性代數(shù)中,矩陣是這樣的(以單位矩陣為例)

其實(shí)該圖也是CSS中矩陣的初始值。但我們的矩陣一般都不會(huì)這么簡(jiǎn)單,都會(huì)有一些初始值,語(yǔ)法如下,其中
a b c e d f 都為數(shù)值,這么寫是為了方便區(qū)分
transform: matrix(a,b,c,d,e,f);
如果你非要用坐標(biāo)來(lái)理解,也可以看成是
transform: matrix(x1, x2, y1, y2, z1,z2)
不過(guò)我擔(dān)心你會(huì)越理解越混。寫成向量形式就是
當(dāng)我們要做變換時(shí),實(shí)質(zhì)上就是對(duì)初始值添加一些系數(shù),也就是:

所以我們能得到兩個(gè)式子:
x' = ax + cy + e // 即:x坐標(biāo)
y' = bx + dy + f // 即:y坐標(biāo)
記住了,ax+cy+e為變換后的水平坐標(biāo),bx+dy+f表示變換后的垂直位置。
說(shuō)了這么一大堆,矩陣到底和圖形變換有什么關(guān)系?我怎么越看越迷糊了?
? 不急,既然要’逆襲‘,就不可能那么簡(jiǎn)單,為加深理解,看一個(gè)例子來(lái)直觀理解一下
transform: matrix(1,o,o,1,3o,3o); /* a=1, b=0, c=0, d=1, e=30, f=30 */
假設(shè)矩陣偏移的中心點(diǎn)是 (0,0) , 即 x=0; y=0; 有如下式子
x' = ax + cy + e = 1*0 + 0*0 + 30 = 30
y' = bx + dy + f = 0*1 + 1*0 + 30 = 30
于是,我們得到偏移后的坐標(biāo)為 (30,30);這是什么變化?相信大家都猜到了,沒(méi)錯(cuò),這是平移變化,即
transform: translate(30px, 30px)
聰明的你或許已經(jīng)看破了,對(duì)于平移效果,其實(shí)矩陣公式是這樣的;
transform: matrix(跟我無(wú)關(guān), 我不知道, 一邊玩去, 愛(ài)咋咋地, x軸偏移量,y軸偏移量)
前面是個(gè)參數(shù)都是沒(méi)用的,因?yàn)橄禂?shù)(x,y) 為0.
? 平移容易理解,那么,其他效果呢? 我們來(lái)看看縮放:
? 或許你也猜到了,和縮放相關(guān)的也是兩個(gè)參數(shù),是的,完全正確,假設(shè)比例是s,則有matrix(s, 0, 0, s, 0, 0),于是得到:
x' = ax+cy+e = s*x+0*y+0 = s*x;
y' = bx+dy+f = 0*x+s*y+0 = s*y;
也就是
transform: matrix(sx,0,0,sy,0,0); 等同于 scale(sx, sy);
? 前兩個(gè)都還能接受,旋轉(zhuǎn)就選對(duì)復(fù)雜些,需要用到三角函數(shù),使用參數(shù)如下:
matrix(cosθ,sinθ,-sinθ,cosθ,0,0)
結(jié)合矩陣公式有
x' = x*cosθ-y*sinθ+0 = x*cosθ-y*sinθ
y' = x*sinθ+y*cosθ+0 = x*sinθ+y*cosθ
我們可能計(jì)算得到如下一個(gè)式子:
transform: matrix(0.866025,0.500000,-0.500000,0.866025,0,0);
好難好難,其實(shí)說(shuō)實(shí)在的,要是我肯定不這么寫,太麻煩了,用 rotate(20deg) 還是直接很多。
? 拉伸(skew) 也比較復(fù)雜,也是用到三角函數(shù),使用參數(shù)如下,
matrix(1,tan(θy),tan(θx),1,0,0)
套用矩陣公式計(jì)算結(jié)果為:
x' = x+y*tan(θx)+0 = x+y*tan(θx)
y' = x*tan(θy)+y+0 = x*tan(θy)+y
對(duì)應(yīng)于skew(θx + "deg",θy+ "deg")這種寫法。
好麻煩好麻煩,我也不想用 matrix 來(lái)表示拉伸。
matrix 工具
估計(jì)你看完 martix 還是滿腦渾水,推薦一個(gè)測(cè)試工具矩陣變形,可以在里面自己多做些嘗試。
# 視距 - perspective
? 視距表示觀察者距離圖像的距離,是繪制3d效果必不可少的屬性之一??梢曰仡櫼幌麻_(kāi)篇第一張圖片,眼睛位置就是觀察者位置,d + z (z可以是負(fù)數(shù)) 就表示的是視距。
? 視距的表示有兩種方法,一種是:
transform: perspective(100px);
另一種是
perspective: 100px;
前者作為transform的值來(lái)使用,后者作為transform的前置屬性,不過(guò)需要兩種效果不太一致,前置屬性需要設(shè)置在父元素上生效。
# 后語(yǔ)
? 本文主要介紹 transform 的可選值以及它們的具體用法,知識(shí)點(diǎn)有些多需要大家慢慢消化,另外前置屬性還算相對(duì)容易一些,可以自行去了解一下用法。本文如果有不對(duì)或不好的地方,歡迎到評(píng)論區(qū)交流。