HTML5 CSS3 transform

理解CSS3 transform中的Matrix(矩陣)

一、哥,我被你嚇住了

打架的時候會被塊頭大的嚇住,學習的時候會被奇怪名字嚇住(如“拉普拉斯不等式”)。這與情感化設計本質一致:界面設計好會讓人覺得這個軟件好用!

所以,當看到上面“Matrix(矩陣)”的時候,難免會心生畏懼(即使你已經學過),正常心理。實際上,這玩意確實有點複雜。

然而,這卻是屌絲逆襲的一個好機會。

CSS同行間:
你是不是有這樣的感覺:哎呀呀,每天就是對着設計圖切頁面,貌似技術沒有得到實質性地提升啊,或者覺得日後高度有限!

我們應該都知道二八法則(巴萊多定律),即任何一組東西中,最重要的只佔其中一小部分,約20%,其餘80%的儘管是多數,卻是次要的。如果你有上述的感覺,那你就屬於那80%, 一抓一大把,沒有特色的頁面仔。

CSS門檻低,無需程序基礎或數學邏輯能力,也能做出點自我感覺不錯的東西。然而,你自己也應該清楚的,一般你能輕鬆學到的東西,別人也可以。因此,如果你想擠進那20%的行列,就要學到一般人學不到的深度,學到一般人學不了的東西。自然,是需要更多額外的努力的。如果每次你都比別人努力一點點,何愁不比他人高出幾等。人年輕的時候,貴在堅持!

而這裏的CSS矩陣就是展現你與其他芸芸同行差異的好契機。很多人看到名字就畏懼了,看到奇怪的數學書寫就嚇退了;而你沒有,迎難而上,把搖手機的時間用在理解矩陣上。自然,你就冒尖了一點。類似的,很多其他CSS方面的東西,你也比別人多深入學習一點,怎麼可能就是個普通的頁面仔呢?

因此,從這裏開始,擺脫那80%的行列吧!

僞同行間:
雖然都是從事計算機,雖然都是從事互聯網,雖然都是寫代碼的,(據說)寫JAVA的瞧不起寫JavaScript的,寫JavaScript的瞧不起寫CSS的。這可以理解,雖然養雞養鴨成爲富翁的不在少數,但是,一說你是農村養雞的,怎麼樣?上海專業的丈母孃們的視線立馬下降60°——被BS了。倒不是因爲你是幹農業的,而是“雞”的問題;如果說你是飼養斯里蘭卡藍孔雀的,得,挑剔的丈母孃們說不定就會正臉看看(唷,斯里蘭卡,國外貨;唷,孔雀,高檔貨)。

同樣的,如果你掌握的CSS都是些“砌磚頭”的活(雖然砌磚頭也是大學問),被無視也情理之中。但是,矩陣這個東西,就是扭轉乾坤(網稱“逆襲”)的好東西:CSS中也是有複雜的高檔貨的。再忽悠些“圖形算法、位置計算”之類的詞句,嘿嘿,立馬看法從變成

二、何爲矩陣?

矩陣可以理解爲方陣,只不過,平時方陣裏面站的是人,矩陣中是數值:
方陣 矩陣示意 張鑫旭-鑫空間-鑫生活

而所謂矩陣的計算,就是兩個方陣的人(可以想象成古代的方陣士兵)相互衝殺。

CSS3中的矩陣
CSS3中的矩陣指的是一個方法,書寫爲matrix()matrix3d(),前者是元素2D平面的移動變換(transform),後者則是3D變換。2D變換矩陣爲3*3, 如上面矩陣示意圖;3D變換則是4*4的矩陣。

有些迷糊?恩,我也覺得上面講述有些不合時宜。那好,我們先看看其他東西,層層漸進——transform屬性。

具體關於transform屬性具體內容可以點擊這裏補個課。稍微熟悉的人都知道,transform中有這麼幾個屬性方法:

.trans_skew { transform: skew(35deg); }
.trans_scale { transform:scale(1, 0.5); }
.trans_rotate { transform:rotate(45deg); }
.trans_translate { transform:translate(10px, 20px); }

斜拉(skew),縮放(scale),旋轉(rotate)以及位移(translate)。

那你有沒有想過,爲什麼transform:rotate(45deg);會讓元素旋轉45°, 其後面運作的機理是什麼呢?

下面這張圖可以解釋上面的疑問:
transform屬性方法本質實現 張鑫旭-鑫空間-鑫生活

無論是旋轉還是拉伸什麼的,本質上都是應用的matrix()方法實現的(修改matrix()方法固定幾個值),只是類似於transform:rotate這種表現形式,我們更容易理解,記憶與上手。

換句話說,理解transformmatrix()矩陣方法有利於透徹理解CSS3的transform屬性,這就與那80%的也會應用但只知表象的人拉開了差距!

OK,現在上面提到的CSS3矩陣解釋應該說得通了。

三、矩陣應用場景

雖然題目寫的是“transform中的Matrix”,實際上,在CSS3以及HTML5的世界裏,這玩意還是涉獵蠻廣的,如SVG以及canvas.
事實上,關於矩陣,我之前曾經介紹過,是在介紹IE瀏覽器下的Matrix矩陣濾鏡的時候說過,IE的濾鏡矩陣與CSS中的矩陣雖然寫法上差異較大,但是,矩陣計算的原來是一致的。只是之前的介紹主要是IE下的旋轉與縮放,同時也不是很深入,因此還有有些侷限的。

四、transform與座標系統

用過transform旋轉的人可以發現了,其默認是繞着中心點旋轉的,而這個中心點就是transform-origin屬性對應的點,也是所有矩陣計算的一個重要依據點(下圖參考自dev.opera.com)。
transform座標系統

當我們通過transform-origin屬性進行設置的時候,矩陣相關計算也隨之發生改變。反應到實際圖形效果上就是,旋轉拉伸的中心點變了!

舉例來說,如果偶們設置:

-webkit-transform-origin: bottom left;

則,座標中心點就是左下角位置。於是動畫(例如圖片收縮)就是基於圖片的左下角這一點了:
動畫的起始點 張鑫旭-鑫空間-鑫生活

上圖效果可以點擊這裏查看(Chrome瀏覽器)。

再舉個稍微難理解的例子,我們如果這樣設置:

transform-origin: 50px 70px;

則,中心點位置有中間移到了距離左側50像素,頂部70像素的地方(參見下圖),而此時的(30, 30)的座標爲白點所示的位置(這個位置後面會用到)。
中心座標數值偏移的理解 張鑫旭-鑫空間-鑫生活

仔細看看,是不是很快就理解了哈~~

五、準備好了沒?重頭戲來了

CSS3 transformmatrix()方法寫法如下:

transform: matrix(a,b,c,d,e,f);

嚇住了吧,這多參數,一個巴掌都數不過來。好吧,如果你把a~f這6個參數想象成女神的名詞,你會覺得,世界不過如此嘛~~

實際上,這6參數,對應的矩陣就是:
矩陣參數與矩陣對應關係 張鑫旭-鑫空間-鑫生活

注意書寫方向是豎着的

上面提過,矩陣可以想象成古代的士兵方陣,要讓其發生變化,只有與另外一個士兵陣火拼就可以了,即使這是個小陣。

反應在這裏就是如下轉換公式:
CSS3中矩陣位置計算公式 張鑫旭-鑫空間-鑫生活

其中,xy表示轉換元素的所有座標(變量)了。那後面的ax+cy+e怎麼來的呢?
//zxx:大學時候線性代數知識,懂的人這裏可以直接跳過

很簡單,3*3矩陣每一行的第1個值與後面1*3的第1個值相乘,第2個值與第2個相乘,第3個與第3個,然後相加,如下圖同色標註:
矩陣計算的同色標註

ax+cy+e的意義是什麼?
記住了,ax+cy+e爲變換後的水平座標,bx+dy+f表示變換後的垂直位置。

又迷糊了?不急,一個簡單例子就明白了。

假設矩陣參數如下:

transform: matrix(1, 0, 0, 1, 30, 30); /* a=1, b=0, c=0, d=1, e=30, f=30 */

現在,我們根據這個矩陣偏移元素的中心點,假設是(0, 0),即x=0y=0

於是,變換後的x座標就是ax+cy+e = 1*0+0*0+30 =30y座標就是bx+dy+f = 0*0+1*0+30 =30.

於是,中心點座標從(0, 0)變成了→(30, 30)。對照上面有個(30, 30)的白點圖,好好想象下,原來(0,0)的位置,移到了白點的(30, 30)處,怎麼樣,是不是往右下方同時偏移了30像素哈!!

實際上transform: matrix(1, 0, 0, 1, 30, 30);就等同於transform: translate(30px, 30px);. 注意:translaterotate等方法都是需要單位的,而matrix方法e, f參數的單位可以省略。

一例勝萬語,您可以狠狠地點擊這裏:matrix(1,0,0,1,30,30)實例demo

在現代瀏覽器下,會有類似下面動圖的效果:
30*30像素偏移示意

效果只是表象的,我想到了一個更好的idea去表現矩陣到底是如何變換的,您可以狠狠地點擊這裏:matrix分解變換演示

爲了提高性能,demo中每個單元分解成了5px * 5px的區域。演示分兩步,先是演示每個單元的位置是如何計算的,接着動畫表現其位置的偏移。

這個demo所做的工作就是把瀏覽器瞬間完成的計算和渲染變成了可控的分步顯示,這樣,大家就可以很直觀地看出,這個矩陣計算到底是如何起作用的。下圖爲正在演示過程中的截圖:
矩陣計算分解演示demo截圖 張鑫旭-鑫空間-鑫生活

//zxx:由於默認100毫秒間隔不斷渲染,因此如果你電腦CPU或是瀏覽器hold不住,可以取消“自動演示”的勾選,然後,點擊左邊的按鈕手動分步查看。

總結
聰明的你可能以及意識到了,尼瑪matrix表現偏移就是:

transform: matrix(與我無關, 哪位, 怎麼不去高考, 打麻將去吧, 水平偏移距離, 垂直偏移距離);

你只要關心後面兩個參數就可以了,至於前面4個參數,是牛是馬,是男是女都沒有關係的。

六、transform matrix矩陣與縮放,旋轉以及拉伸

偏移是matrix效果中最簡單,最容易理解的,因此,上面很詳盡地對此進行展開說明。下面,爲了進一步加深對matrix的理解,會簡單講下matrix矩陣與縮放,旋轉以及拉伸效果。

縮放(scale)
上面的偏移只要關心最後兩個參數,這個縮放也是隻要關心兩個參數。哪兩個呢?

如果你足夠明察秋毫,應該已經知道了,因爲上面多次出現的:

transform: matrix(1, 0, 0, 1, 30, 30);

已經出賣了。

發現沒,matrix(1, 0, 0, 1, 30, 30);的元素比例與原來一樣,1:1, 而這幾個參數中,有兩個1, 啊哈哈!沒錯,這兩個1就是縮放相關的參數。

其中,第一個縮放x軸,第二個縮放y軸。

用公式就很明白了,假設比例是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;

也就是matrix(sx, 0, 0, sy, 0, 0);,等同於scale(sx, sy);

好了,至此,無需多說了……

眼見爲實,因此demo還是要滴,您可以狠狠地點擊這裏:matrix矩陣與縮放demo

爲了避免元素比例放大時候遮蓋上面的文本框以及描述位子,因此,將元素的座標原點遷至了左上角。

matrix矩陣縮放demo效果截圖

旋轉(rotate)
旋轉相比前面兩個要更高級些,要用到(可能勾起學生時代陰影的)三角函數。

方法以及參數使用如下(假設角度爲θ):

matrix(cosθ,sinθ,-sinθ,cosθ,0,0)

結合矩陣公式,就有:

x' = x*cosθ-y*sinθ+0 = x*cosθ-y*sinθ
y' = x*sinθ+y*cosθ+0 = x*sinθ+y*cosθ

這個與IEMatrix濾鏡中的旋轉是有些類似的(M11表示矩陣第1行第1個(參數a),M21表示矩陣第2行第一個(參數b)……):

filter:progid:DXImageTransform.Microsoft.Matrix(M11=cosθ,M21=sinθ,M12=-sinθ,M22=cosθ');

哎呀呀,四個參數,我記不住啊!莫慌,我們可以這樣子記憶:
CS-SC:初三-上牀,對稱結構,這下忘不了了吧~~

您可以狠狠地點擊這裏:transform matrix矩陣與旋轉demo

matrix矩陣旋轉效果demo頁面截圖 張鑫旭-鑫空間-鑫生活

不過,說句老實話,就旋轉而言,rotate(θdeg)這種書寫形式要比matrix簡單多了,首先記憶簡單,其次,無需計算。例如,旋轉30°,前者直接:

transform:rotate(30deg);

而使用matrix表示則還要計算cossin值:

transform: matrix(0.866025,0.500000,-0.500000,0.866025,0,0);

拉伸(skew)
拉伸也用到了三角函數,不過是tanθ,而且,其至於b, c兩個參數相關,書寫如下(注意y軸傾斜角度在前):

matrix(1,tan(θy),tan(θx),1,0,0)

套用矩陣公式計算結果爲:

x' = x+y*tan(θx)+0 = x+y*tan(θx) 
y' = x*tan(θy)+y+0 = x*tan(θy)+y

對應於skew(θx + "deg",θy+ "deg")這種寫法。

其中,θx表示x軸傾斜的角度,θy表示y軸,兩者並無關聯。

還是靠實例說話吧,您可以狠狠地點擊這裏:matrix矩陣與拉伸demo

在Chrome下可以很動態地查看不同傾斜角度對應的拉伸的效果:
拉伸效果demo頁面截圖

七、既然有簡單的skew, rotate..,那matrix有何用?

我想有人會奇怪,既然CSS3 transform中提供了像skewrotate效果,那還需要掌握和熟悉讓人頭大的矩陣方法幹嘛呢?

好問題,確實,對於一般地交互應用,transform屬性默認提供的些方法是足夠了,但是,一些其他的效果,如果transform屬性沒有提供接口方法,那你又該怎麼辦呢?比方說,“鏡像對稱效果”!

沒轍了吧,這是,就只能靠matrix矩陣了。要知道,matrix矩陣是transform變換的基礎,可以應付很多高端的效果,算是一種高級應用技巧吧。掌握了基礎,才能兵來將擋水來土掩啊。

OK,這裏就演示下,如何使用CSS3 transform matrix矩陣實現鏡像效果。

這個有點難度,因此,我們先看demo,您可以狠狠地點擊這裏:matrix與鏡像對稱效果demo

框框中輸入旋轉的角度值(用來確定鏡像的對稱軸),然後失去焦點,就會呈現出對應的鏡像對稱效果了:
鏡像對稱效果操作示意 張鑫旭-鑫空間-鑫生活
鏡像對稱效果截圖

您可以在FireFox或是Chrome等瀏覽器上體驗下matrix實現的鏡像漸變效果。

demo頁面中的一個軸是爲了便於理解我加上的效果,實際上,在鏡像對稱的時候軸是看不見的。

軸圍繞的那個點就是CSS3中transform變換的中心點,自然,鏡像對稱也不例外。因爲該軸永遠經過原點,因此,任意對稱軸都可以用y = k * x表示。則matrix表示就是:

matrix((1-k*k) / (1+k*k), 2k / (1 + k*k), 2k / (1 + k*k), (k*k - 1) / (1+k*k), 0, 0)

這個如何得到的呢?
啊,高中數學來了,就當再高考一次吧,如下圖,已經y=kx,並且知道點(x, y)座標,求其對稱點(x’, y’)的座標?
鏡像漸變題目 張鑫旭-鑫空間-鑫生活

很簡單,一是垂直,二是中心點在軸線上,因此有:

(y-y') / (x - x') = -1/ k → ky-ky' = -x+x'
(x + x') / 2 * k = (y + y')/2 → kx+kx' = y+y'

很簡單的,把x'y'提出來,就有:

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;

再結合矩陣公式:
x' = ax+cy+e;
y' = bx+dy+f;

我們就可以得到:
a = (1-k*k)/(k*k+1);
b = 2k/(k*k+1);
c = 2k/(k*k+1);
d = (k*k-1)/(k*k+1);

也就是上面matrix方法中的參數值啦!

下圖爲自己計算的草稿:
鏡像矩陣參數計算草稿

八、3D變換中的矩陣

3D變換雖然只比2D多了一個D,但是複雜程度不只多了一個。從二維到三維,是從4到9;而在矩陣裏頭是從3*3變成4*4, 9到16了。

其實,本質上很多東西都與2D一致的,只是複雜度不一樣而已。這裏就舉一個簡單的3D縮放變換的例子。

對於3D縮放效果,其矩陣如下:
3D比例變換矩陣圖 張鑫旭-鑫空間-鑫生活

代碼表示就是:

transform: matrix3d(sx, 0, 0, 0, 0, sy, 0, 0, 0, 0, sz, 0, 0, 0, 0, 1)

您可以狠狠地點擊這裏:matrix3d下的3D比例變換demo

補充於2013-04-24
關於3D變換,可以參見邪惡的這篇文章:“CSS3 3D transform變換,不過如此!

九、結束語

想了想,沒什麼要嘮叨的。文中觀點若是存在疑問或不準確的,歡迎指正。感謝閱讀!

參考文章:
Understanding the CSS Transforms Matrix
CSS3前端開發中需要用到的變換矩陣 

原創文章,轉載請註明來自張鑫旭-鑫空間-鑫生活[http://www.zhangxinxu.com]
本文地址:http://www.zhangxinxu.com/wordpress/?p=2427

發佈了34 篇原創文章 · 獲贊 5 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章