CSS 3D變換

一、寫在前面的秋褲

早在去年的去年,我就大肆介紹了2D transform相關內容。看過海賊王的都知道,帶D的傢伙都不是好惹的,2D我輩尚可以應付,3D的話,呵呵,估計我等早就在千里之外被其霸氣震暈了~~

看看下圖女帝的動作以及神情,就可以知道名字帶D的傢伙的厲害!
路飛女帝D族的厲害 張鑫旭-鑫空間-鑫生活

最近折騰iPad的一些東西,有一些3D效果的交互。有些事情,總以爲是遙遠的未來,誰知真正發生的時候說來就來,比如說一顆想結婚的心,又比方說在實際項目中折騰3D transform效果。

哭泣鑫表情 張鑫旭-鑫空間-鑫生活

然而,雖然以前折騰過3D變換效果(webkit),但都是依葫蘆畫瓢,囫圇吞棗,真正要輕鬆實現想要的3D效果,是需要深入理解的,於是,此時的自己苦逼了,淚奔ing……

木有辦法,找資料,自己思考學習唄,當我看到下面這張基本圖的時候,我的右側的濃眉毛不由自主抖動了兩下,呵,呵呵~~
3D變換座標圖解 張鑫旭-鑫空間-鑫生活

這個長得像原子核一樣的是什麼東東?那像章魚哥一樣四處橫生的箭頭好嚇人哦!後面怎麼還有一個蒼蠅拍??  CSS好可怕,我要回去找媽媽……

想必大部分的同行應該跟我一樣,沒有愛因斯坦爺爺的智商,沒有上鏡需要把表摘掉的爸爸。因此,那些術語連篇的CSS3 3D transform介紹的資料過於耀眼,無法直視。怎麼辦?

好吧,佛家有云,我不入地獄誰入地獄。這裏,我就從凡人們的視角說說CSS3 3D transform的一些東西,希望說的東西比較親民,不要嚇着大家。

二、首先,情感化認識

我覺得吧,要想理解一個東西,最好先有一些感性的認識。

CSS3中的3D變換效果,本質上就是我們OOXX時候各種姿勢的變換,又稱各種體位的變換。

雖然都是成年人,但考慮到仍有不少窩中待守的雛鳥,如果上面的解釋想不過來,就想想以下這些:
1. 下圖的這些人在幹嘛?

跳水?NO, No, No!! 記住,他們不是在跳水,是在做3D變換!!!

2. 下圖可愛baby在幹嘛

廣播體操?NO, No, No!! 記住,他不是在做操,是在做3D變換!!!

3. 來到2次元,下圖這個妹子在這幅姿態稱爲:
 鑫表情 性感 色
賣萌?NO, No, No!! 記住,他不是在賣萌,是在做3D變換!!!

哈哈哈哈,是否意識到:在顯示世界中,一切的動作(包括上面巨乳萌妹所引發的精蟲上腦),都是屬於3D transform變換。 因此,要學習與理解3D transform變換很簡單,一句話,到現實世界找個東西映射一下即可。

三、認識的突破口:rotateX, rotateY, rotateZ

3D transform中有下面這三個方法:

  • rotateX( angle )
  • rotateY( angle )
  • rotateZ( angle )

理解了這三個方法,後面更難懂的perspective就好下手了,可以說是突破口!

rotate旋轉的意思,rotateX旋轉X軸,rotateY旋轉Y軸,rotateZ旋轉Z軸……

什麼X軸/Y軸/Z軸,這幾個詞從我嘴裏一出來,別說你們,我自己都暈了~~

趕快,從現實世界找對應東西理解(參照下面人的旋轉):
鄒凱的體操單槓運動是rotateX
單槓

蔡依林姐姐的鋼管舞是rotateY
蔡依林-鋼管舞 張鑫旭-鑫空間-鑫生活

旋轉飛刀的特技表演是rotateZ
飛刀魔術

還是理解不過來?好吧,假設你是男的,以你的女朋友舉例,假如原本你和她面對面站着,然後你——
從正面將其推到就是rotateX
妹子推到與transform rotateX 張鑫旭-鑫空間-鑫生活

讓其原地轉個90度欣賞其側面的豐滿曲線就是rotateY
妹子推到與transform rotateY 張鑫旭-鑫空間-鑫生活

把妹子抱到牀上側面躺着就是rotateZ
妹子推到與transform rotateZ 張鑫旭-鑫空間-鑫生活

於是,下面CSS世界中的簡單3D效果是不是更容易理解了呢?!
transform rotateX(45deg)的效果圖 張鑫旭-鑫空間-鑫生活 transform rotateY(45deg)的效果圖 張鑫旭-鑫空間-鑫生活 transform rotateZ(45deg)的效果圖 張鑫旭-鑫空間-鑫生活

//zxx: 下面爲廣告~~注意不要勿點~~嘻嘻~~

四、必不可少的perspective屬性

perspective的中文意思是:透視,視角!

perspective屬性的存在與否決定了你所看到的是2次元的還是3次元的,也就是是2D transform還是3D transform. 這不難理解,沒有透視,不成3D.

我們初中學美術,或者學建築的同學肯定接觸過透視的一些東西:
3D透視 張鑫旭-鑫空間-鑫生活 3D透視 張鑫旭-鑫空間-鑫生活

不過,CSS3 3D transform中的透視的透視點與上面兩張示例圖是不同的:CSS3 3D transform的透視點是在瀏覽器的前方

或者這麼理解吧:顯示器中3D效果元素的透視點在顯示器的上方(不是後面),近似就是我們眼睛所在方位!

比方說,一個1680像素寬的顯示器中有張美女圖片,應用了3D transform,同時,該元素或該元素父輩元素設置的perspective大小爲2000像素。則這張美女多呈現的3D效果就跟你本人在1.2個顯示器寬度的地方(1680*1.2≈2000)看到的真實效果一致!!
1680寬度像素顯示器與3D transform視角大小示意 張鑫旭-鑫空間-鑫生活

五、translateZ幫你尋找透視位置

如果說rotateX/rotateY/rotateZ可以幫助理解三維座標,則translateZ則可以幫你理解透視位置。

我們都知道近大遠小的道理,對於沒有rotateX以及rotateY的元素,translateZ的功能就是讓元素在自己的眼前或近或遠。比方說,我們設置元素perspective爲201像素,如下:

perspective: 201px;

則其子元素,設置的translateZ值越小,則子元素大小越小(因爲元素遠去,我們眼睛看到的就會變小);translateZ值越大,該元素也會越來越大,當translateZ值非常接近201像素,但是不超過201像素的時候(如200像素),該元素的大小就會撐滿整個屏幕(如果父輩元素沒有類似overflow:hidden的限制的話)。因爲這個時候,子元素正好移到了你的眼睛前面,所謂“一葉蔽目,不見泰山”,就是這麼回事。當translateZ值再變大,超過201像素的時候,該元素看不見了——這很好理解:我們是看不見眼睛後面的東西的!

再生動的文字描述也不如一個實例來得直觀,您可以狠狠地點擊這裏:translateZ方法輔助理解perspective視角demo

建議Chrome瀏覽器下訪問,可以使用range控件,演示效果更贊,如下截圖:-100時候最小,200時候超級滿屏(垂直方向因特殊佈局限制沒有顯示),250的時候因爲元素已經在視點之外,因此是一片空白(看不見)。
translateZ -100像素最遠距離最小顯示 張鑫旭-鑫空間-鑫生活 translateZ 200像素時候超級大的顯示 translateZ爲250像素時候元素在視區之外,因此看不見是空白 張鑫旭-鑫空間-鑫生活

六、perspective屬性的兩種書寫

perspective屬性有兩種書寫形式,一種用在舞臺元素上(動畫元素們的共同父輩元素);第二種就是用在當前動畫元素上,與transform的其他屬性寫在一起。如下代碼示例:

.stage {
    perspective: 600px;
}

以及:

#stage .box {
    transform: perspective(600px) rotateY(45deg);
}

您可以狠狠地點擊這裏:perspective屬性的兩種書寫demo

結果如下縮略圖:
CSS3 transform perspective兩種書寫形式demo效果截圖

從上圖我們貌似可以看到,雖然書寫的形式,屬性名稱不一致,但是,效果貌似是一樣的~~果真是這樣嗎???

實際上不然,上面的demo上下兩個效果之所以會一樣,是因爲舞臺上只有一個元素,因此,發生了巧合,其正好表現一樣了。如果,如果舞臺上有很多個元素,則兩種書寫形式的表現差異就會立馬顯示出來了!

您可以狠狠地點擊這裏:舞臺多元素下的perspective兩種書寫對比demo

demo頁面效果縮略圖如下(因背景色隨機,可能與下圖有差異):
不同transform perspective書寫下的表現差異

好吧,圖中的效果其實不難理解。上面舞臺整個作爲透視元素,因此,顯然,我們看到的每個子元素的形體都是不一樣的;而下面,每個元素都有一個自己的視點,因此,顯然,因爲rotateY的角度是一樣的,因此,看上去的效果也就一模一樣了!

關於Chrome瀏覽器以及透視盲區
在Chrome瀏覽器下,要想看到完整的3D效果,還需要3D變換元素正好在窗體的垂直居中位置,因此,在Chrome瀏覽器下,生成了兩個位置居中的按鈕,幫助您看到想要的效果:
Chrome瀏覽器下位置居中按鈕 張鑫旭-鑫空間-鑫生活
Chrome瀏覽器下舞臺垂直居中3D效果顯示

當我們改變第一個range控件值爲200的時候,您會發現右側第三個元素看不見了:
200值的時候有元素看不見

這不難理解,前面一排門,每個門都是1米,你距離門2米,顯示,當所有門都開了45°角的時候,此時,距離中間門右側的第二個門正好與你的視線平行,這個門的門面顯然就什麼也看不到。這就是爲什麼上面右側第三個門一片空白的元素——特定的視角以及距離形成的視覺盲區。

七、理解perspective-origin

perspective-origin這個屬性超級好理解,表示你那雙色迷迷的眼睛看的位置。默認就是所看舞臺或元素的中心。有時候,我們對中心的位置是不感興趣的,希望視線放在其他一些地方。比方說
不同視線落地位置對應不同的perspective-origin值

一圖勝千言,屌絲男們這個應該都懂的。

下面爲立方體的實際應用透視效果圖:

perspective-origin: 25% 75%;

立方體不同透視角度的效果 張鑫旭-鑫空間-鑫生活

八、transform-style: preserve-3d

transform-style屬性也是3D效果中經常使用的,其兩個參數,flat|preserve-3d. 前者flat爲默認值,表示平面的;後者preserve-3d表示3D透視。

preserve-3d符合我們真實世界的思維認識。比方說,你讓妹子右轉了45度,此時妹子腦袋左轉45度想你吐舌賣萌,妹子的臉蛋應該和你是面對面平行的。
妹子推到與transform rotateY 張鑫旭-鑫空間-鑫生活
應用transform-style: preserve-3d聲明的元素確實是這樣表現的,但是,如果使用默認的flat值,其效果表現——恕我想象力有限——想不通:妹子的臉還是左轉45度的,同時腦袋似乎移到了身體以外的地方

因此,基本上,我們想要根據現實經驗實現一些3D效果的時候,transform-style: preserve-3d是少不了的。一般而言,該聲明應用在3D變換的兄弟元素們的父元素上,也就是舞臺元素。

九、backface-visibility

在顯示世界中,我們無法穿過軟妹A看到其身後的軟妹B或C或D;但是,在CSS3的3D世界中,默認情況下,我們是可以看到背後的元素(也不知可不可以透視妹子的衣服~)!
看不到後面的軟妹,哦呵呵,  backface-visibility, 張鑫旭-鑫空間-鑫生活

因此,爲了切合實際,我們常常會這樣設置,使後面元素不可見:

backface-visibility:hidden;

十、實際應用-圖片的旋轉木馬效果

您可以狠狠地點擊這裏:圖片的旋轉木馬效果demo

建議在足夠新版本的FireFox瀏覽器或Safari瀏覽器下觀看,Chrome可能需要居中定位查看,下圖爲效果縮略圖:
圖片3D旋轉木馬效果截圖 張鑫旭-鑫空間-鑫生活

原理:
那些看上去很酷酷的CSS3 3D效果其實就顛來倒去那幾個屬性(本文提到的這幾個),折騰來折騰去,這裏這個效果顯然也是如此。

首先HTML結構,如下:

舞臺
    容器
        圖片
        圖片
        圖片
        ...

對於舞臺,很簡單,加個視距,比方說800像素:

 perspective: 800px;

對於容器,很簡單,加個3D視圖聲明,如下:

transform-style: preserve-3d;

然後就是圖片們了。爲了不至於產生類似DNA的螺旋狀效果,我們讓所有圖片position:absolute,公用同一個中心點。

顯然,圖片旋轉木馬是類似鋼管舞旋轉的運動,因此,我們關心的是rotateY的大小。

因爲要正好繞成一個圈,因此,圖片rotateY值正好0~360等分,於是,如果有9張圖片,則每個圖片的旋轉角度累加40(360 / 9 = 40)度即可。因此有:

img:nth-child(1) { transform: rotateY(   0deg ); }
img:nth-child(2) { transform: rotateY(  40deg ); }
img:nth-child(3) { transform: rotateY(  80deg ); }
img:nth-child(4) { transform: rotateY( 120deg ); }
img:nth-child(5) { transform: rotateY( 160deg ); }
img:nth-child(6) { transform: rotateY( 200deg ); }
img:nth-child(7) { transform: rotateY( 240deg ); }
img:nth-child(8) { transform: rotateY( 280deg ); }
img:nth-child(9) { transform: rotateY( 320deg ); }

這樣就好了嗎?

No, No, No!!!

想想看那,雖然9個絕色美女每個人的方位不一樣,但都站在同一個點上,早就擠作一團,A罩都擠成C了,顯然是不行的(見下圖只設置rotateY)!我們需要拉開空間~~

只設置rotateY時候,衆多美女圖片擠作一團

如何拉開空間,很簡單。

想想看那:9個美女,分別面朝東南西北共9個不同方位,她們只要每個人向前走個4~5步,美女們之間的空間不久拉開了,呈現圓形了!想象一下夜空中,禮花綻開的場景~~

這裏的向前走4~5步,聰明的人應該已經知道了,就是本文提到的translateZ, 當translateZ爲正值的時候,元素會向其面對的方向走去;如果元素無旋轉,就會朝顯示器走來!!

現在只剩下一個問題了,美女們要向前走多遠呢??

這個距離是有計算公式滴!

拿本demo距離,每張美女圖片的寬度是128像素,因此,有如下理想方位效果圖:
旋轉木馬效果理想方位圖 張鑫旭-鑫空間-鑫生活

上圖中紅色標註的r就是的demo頁面中圖片要translateZ的理想值(該值可以讓所有圖片無縫圍成一個圓)!

r的計算很簡單,有初中數學水平的人應該都會:

r = 64 / Math.tan(20 / 180 * Math.PI) ≈ 175.8

demo頁面爲了好看,圖片之間留了點間距,使用的translateZ的值爲175.8 + 20 = 195.8.
旋轉木馬demo頁面translateZ值大小

最後的最後,要讓木馬旋轉起來,只要讓容器每次旋轉40度就可以了。

節省篇幅,具體的JavaScript操作代碼就不展示了,您有興趣可以查看demo頁面源代碼。

理解了旋轉木馬3D效果實現原理,基本上,其他些3D效果可以輕鬆駕馭了,因此,本效果還是值得你花功夫看看滴~~

十一、好吧,結語

理論上,現實世界,及3次元世界中的各種有規律的運動效果都可以使用CSS3 transform 3D方法實現。文章最後的旋轉木馬效果可以說是各類千奇百怪效果中的滄海一粟~~其他各類有的沒有的效果就靠你的大腦就構想了。至於實現嘛,理解了,也就都是小菜。但是,要是不理解,純粹從網上copy些效果代碼,那永遠就是copy的命咯!

文章篇幅已經很長了,我的指頭也敲出老繭來了,就不再囉嗦什麼了。希望本文的嗑叨、賣弄、折騰能夠讓您學習CSS3 3D transform變換的相關東西更加輕鬆點!


原創文章,轉載請註明來自張鑫旭-鑫空間-鑫生活[http://www.zhangxinxu.com]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章