英文原文An Introduction to CSS 3-D Transformscss
愛因斯坦說全部概念都必須介紹給兒童們,若他們沒法瞭解,這些理論就毫無價值。
html
一個元素須要一個透視點才能激活3D空間,有兩種方法能夠獲得透視點:前端
-webkit-transform: perspective(600);
-webkit-perspective: 600;
左邊是使用transform屬性的,右邊使用perspective屬性web
這兩種方法都能觸發3D空間,但卻有所不一樣。首先,使用函數方式能夠方便快捷地對單一元素應用3D變形,可是當你要應用在多個元素上時,它們可能不會按照預期的效果排列。若是你使用一樣的transform屬性應用在多個不一樣位置的元素上,每一個元素都有本身的消失點。爲了不這種滑稽的效果,使用perspective屬性應用在它們的父容器元素上,這樣每一個元素都共享了同一個消失點。瀏覽器
左邊是使用transform屬性的,右邊使用perspective屬性函數
perspective屬性的值決定了3D效果的強度。佈局
你拿一本書平放在面前,看着書感覺一下透視感,perspective屬性值就是眼睛和書之間的距離,距離越遠,數值越大,透視感越小;距離越近,數值越小,透視感越強。動畫
默認狀況下,3D空間的消失點位於空間的正中央,你能夠經過perspective-origin屬性改變消失點的位置。設計
CSS3d
-webkit-perspective-origin: 25% 75%;
做爲一個Web設計師,你可能很是熟悉二維世界,X和Y,水平和垂直方向。在perspective建立的三維空間中,咱們能夠在三個維度上任意變換一個元素。
3D變形使用的是和2D變形相似的transform屬性。若是你熟悉2D變形,你會發現它和基本的3D變形很像。
CSS
rotateX(angle); rotateY(angle); rotateZ(angle); translateZ(tz); scaleZ(sz);
咱們借鑑translateX()這個函數,它令一個元素沿着水平X軸方向平移,而translateZ()函數則是沿着垂直的Z軸方向平移,它可讓3D空間由前日後運做。假設本身做爲觀察者,觀察着電腦屏幕上的某個元素,translateZ函數的正向值(愈來愈大的值)令元素更靠近觀察者,負向值則遠離觀察者。
rotate函數能夠在特定軸向上旋轉元素。它的效果不一樣於你的直覺,經過下圖能夠很直觀的感覺到。
可能不少人直覺中認爲rotateX的效果會是rotateZ那個樣子。
transform函數的一些簡寫:
CSS
translate3d(tx,ty,tz); scale3d(sx,sy,sz); rotate3d(rx,ry,rz,angle);
專家提醒:這些foo3d()變形函數在safari瀏覽器中會觸發硬件加速效果。
須要一些基本的標籤:
HTML
<section class="container"> <div id="card"> <figure class="front">1</figure> <figure class="back">2</figure> </div> </section>
.container元素持有3D空間,#card做爲一張卡片對象。卡片的每一面就是一個獨立的元素:.front和.back。將3d空間內的各個元素獨立化,能夠更容易理解和應用樣式。
咱們準備添加一些3D樣式:首先,對3D容器應用必要的perspective屬性,同時添加任意的高寬或位置屬性:
CSS
.container { width: 200px; height: 260px; position: relative; -webkit-perspective: 800; }
如今#card元素能夠在該3D空間中進行變形了。咱們給#card元素添加絕對位置屬性讓它脫離文檔的流式佈局,再加上width:100%;
和height:100%
,保證該對象的transform-origin能夠在.center的正中央生效。
讓咱們加上CSS3的transition屬性,這樣用戶能夠看到整個變形過程。
CSS
#card { width: 100%; height: 100%; position: absolute; -webkit-transform-style: preserve-3d; -webkit-transition: -webkit-transform 1s; }
.container的perspective僅僅應用在直接後代元素上,在本例中是應用在#card上。爲了讓全部後代元素都繼承父元素的透視效果並在一樣的3D空間中生效,父元素須要通過transform-style:preserve-3d
來傳遞它的透視屬性。若是沒有transform-style,卡片的兩個面都會失去立體效果,而且背面的旋轉效果也會失效。
要將卡片的兩面定位到3D空間中,咱們須要重置這些面元素的2D位置屬性position:absolute。
當卡片的正面朝向觀察者時,爲了隱藏相反的另外一面,也就是背面,咱們可使用backface-visibility:hidden。
CSS
#card figure { display: block; position: absolute; width: 100%; height: 100%; -webkit-backface-visibility: hidden; }
要翻轉.back面,咱們添加基本的3D變形rotateY(180deg)
。
CSS
#card .front { background: red; } #card .back { background: blue; -webkit-transform: rotateY(180deg); }
將兩個面都設置好以後,#card須要一個相應的樣式來翻轉卡片。
CSS
#card.flipped { -webkit-transform: rotateY(180deg); }
如今咱們具有了一個可用的3D對象。爲了翻轉這張卡片,咱們能夠切換flipped類。當.flipped添加到#card上時,#card會旋轉180度,將.back面露出來。
3D卡片對象是3D變形的入門好教材,一旦熟練掌握,你可能但願建立一些真正3D對象,例如棱柱。下面咱們從立方體開始。 立方體的HTML標籤和卡片相似,可是此次,咱們須要六個子元素來建立立方體的六個面:
HTML
<section class="container"> <div id="cube"> <figure class="front">1</figure> <figure class="back">2</figure> <figure class="right">3</figure> <figure class="left">4</figure> <figure class="top">5</figure> <figure class="bottom">6</figure> </div> </section>
先給六個面設置基本的定位和尺寸樣式,一個疊一個放置在容器裏。
CSS
.container { width: 200px; height: 200px; position: relative; -webkit-perspective: 1000; } #cube { width: 100%; height: 100%; position: absolute; -webkit-transform-style: preserve-3d; } #cube figure { width: 196px; height: 196px; display: block; position: absolute; border: 2px solid black; }
對於卡片,咱們只須要翻轉它的背面。對於立方體,須要翻轉六個面中的五個。咱們稱第一面和第二面爲前面和後面,第三第四面爲側面,第五第六面爲頂面和底面。
CSS
#cube .front { -webkit-transform: rotateY(0deg); } #cube .back { -webkit-transform: rotateX(180deg); } #cube .right { -webkit-transform: rotateY(90deg); } #cube .left { -webkit-transform: rotateY(-90deg); } #cube .top { -webkit-transform: rotateX(90deg); } #cube .bottom { -webkit-transform: rotateX(-90deg); }
如今每一個面都旋轉好了,而且只能看到正面。有四個面是垂直於觀察者的,因此他們徹底不可見。而後要使translate函數將他們從中心位置推到正確的邊上。立方體的每一個邊長是200像素,從中心到邊緣,每一個邊須要平移100像素。
CSS
#cube .front { -webkit-transform: rotateY(0deg) translateZ(100px); } #cube .back { -webkit-transform: rotateX(180deg) translateZ(100px); } #cube .right { -webkit-transform: rotateY(90deg) translateZ(100px); } #cube .left { -webkit-transform: rotateY(-90deg) translateZ(100px); } #cube .top { -webkit-transform: rotateX(90deg) translateZ(100px); } #cube .bottom { -webkit-transform: rotateX(-90deg) translateZ(100px); }
注意這裏的translateZ函數緊接在rotate以後。順序對於變形函數來講是很重要的,請花一些時間消化這句話。每個面要先旋轉到正確的朝向,而後沿着各自的朝向向外平移。
如今咱們的立方體看起來能用了,但還沒完成。
對於使用者,咱們的3D變形不該該失真。可是當咱們將元素從Z軸源點移開以後,不管是靠近觀察者仍是遠離觀察者,它都會失真。
爲了讓3D變形看上去嚴謹,Safari先將元素複合,而後對其應用變形效果。也就是說,文本的抗鋸齒效果會一直保持在變形以前的狀態。
爲了解決失真問題,並還原像素,咱們能夠將整個3D對象向後推,這樣它的正面將回到Z軸源點。
CSS
#cube { -webkit-transform: translateZ(-100px); }
咱們須要一個能暴露任意麪的樣式。事實上咱們只須要對整個立方體對象動手腳,在這裏,立方體對象就是#cube。咱們切換類名來應用不一樣的樣式,一種樣式就是一種變形,暴露不一樣的面。
CSS
#cube.show-front { -webkit-transform: translateZ(-100px) rotateY(0deg); } #cube.show-back { -webkit-transform: translateZ(-100px) rotateX(-180deg); } #cube.show-right { -webkit-transform: translateZ(-100px) rotateY(-90deg); } #cube.show-left { -webkit-transform: translateZ(-100px) rotateY(90deg); } #cube.show-top { -webkit-transform: translateZ(-100px) rotateX(-90deg); } #cube.show-bottom { -webkit-transform: translateZ(-100px) rotateX(90deg); }
注意這裏變形函數的次序和每一個面的函數次序相反,首先要把立方體推回Z軸源點,而後旋轉立方體。 完成以後,咱們添加一個transition屬性來展示旋轉時的動畫效果。
CSS
#cube { -webkit-transition: -webkit-transform 1s; }
立方體很容易製做,它是規則的,咱們只須要關心一個度量值。但對於一個不規則的矩形棱柱呢?讓咱們嘗試作一個300像素長,200像素寬,100像素高的棱柱。
HTML標籤和#cube的同樣,但咱們要把cube換成box,容器的樣式保留大部分:
CSS
.container { width: 300px; height: 200px; position: relative; -webkit-perspective: 1000; } #box { width: 100%; height: 100%; position: absolute; -webkit-transform-style: preserve-3d; }
如今定位各個面。每一個面須要設置他們本身的尺寸,較小的面(左、右、頂、底)要定位到容器的正中央,這樣他們能夠方便地旋轉而後置換到外側。較薄的左面和右面設置位置爲left:100px;((300-100)÷2)。較寬大的頂面和底面設置位置爲top:500px((200-100)÷2)。
CSS
#box figure { display: block; position: absolute; border: 2px solid black; } #box .front, #box .back { width: 296px; height: 196px; } #box .right, #box .left { width: 96px; height: 196px; left: 100px; } #box .top, #box .bottom { width: 296px; height: 96px; top: 50px; }
旋轉值能夠和立方體案例中一致,但對於矩形棱柱,平移值須要一些變化。
CSS
#box .front { -webkit-transform: rotateY(0deg) translateZ(50px); } #box .back { -webkit-transform: rotateX(180deg) translateZ(50px); } #box .right { -webkit-transform: rotateY(90deg) translateZ(150px); } #box .left { -webkit-transform: rotateY(-90deg) translateZ(150px); } #box .top { -webkit-transform: rotateX(90deg) translateZ(100px); } #box .bottom { -webkit-transform: rotateX(-90deg) translateZ(100px); }
就像立方體同樣,#box須要六個樣式來暴露各個面。
CSS
#box.show-front { -webkit-transform: translateZ(-50px) rotateY(0deg); } #box.show-back { -webkit-transform: translateZ(-50px) rotateX(-180deg); } #box.show-right { -webkit-transform: translateZ(-150px) rotateY(-90deg); } #box.show-left { -webkit-transform: translateZ(-150px) rotateY(90deg); } #box.show-top { -webkit-transform: translateZ(-100px) rotateX(-90deg); } #box.show-bottom { -webkit-transform: translateZ(-100px) rotateX(90deg); }
本例的HTML標籤和矩形棱柱、立方體、卡片同樣。讓咱們構建一個9個面的木馬。
HTML
<div class="container"> <div id="carousel"> <figure>1</figure> <figure>2</figure> <figure>3</figure> <figure>4</figure> <figure>5</figure> <figure>6</figure> <figure>7</figure> <figure>8</figure> <figure>9</figure> </div> </div>
如今,應用一些基本的佈局樣式。讓咱們用left屬性和right屬性給每一個面之間添加20像素的間距。每一個面的有效寬度爲210像素(其中實際爲186像素,兩邊各2像素邊框,邊框外各10像素空隙,一共210像素)。
CSS
.container { width: 210px; height: 140px; position: relative; -webkit-perspective: 1000; } #carousel { width: 100%; height: 100%; position: absolute; -webkit-transform-style: preserve-3d; } #carousel figure { display: block; position: absolute; width: 186px; height: 116px; left: 10px; top: 10px; border: 2px solid black; }
下一步,旋轉每一個面。該旋轉木馬由9個面構成,要讓9個面圍成一圈,每一個面要旋轉40度(360÷9)。
CSS
#carousel figure:nth-child(1) { -webkit-transform: rotateY(0deg); } #carousel figure:nth-child(2) { -webkit-transform: rotateY(40deg); } #carousel figure:nth-child(3) { -webkit-transform: rotateY(80deg); } #carousel figure:nth-child(4) { -webkit-transform: rotateY(120deg); } #carousel figure:nth-child(5) { -webkit-transform: rotateY(160deg); } #carousel figure:nth-child(6) { -webkit-transform: rotateY(200deg); } #carousel figure:nth-child(7) { -webkit-transform: rotateY(240deg); } #carousel figure:nth-child(8) { -webkit-transform: rotateY(280deg); } #carousel figure:nth-child(9) { -webkit-transform: rotateY(320deg); }
如今每一個面都位於旋轉木馬對象的正中央,像以前製做立方體和矩形棱柱時同樣,每一個面要向外推到正確的位置上。這裏咱們須要機選translate函數的值,看圖:
這張圖是俯瞰該旋轉木馬對象,210像素是每一個面的寬,r就是translate的值,簡單的三角函數運算。
咱們要將每一個面向外推288像素。
CSS
#carousel figure:nth-child(1) { -webkit-transform: rotateY(0deg) translateZ(288px); } #carousel figure:nth-child(2) { -webkit-transform: rotateY(40deg) translateZ(288px); } #carousel figure:nth-child(3) { -webkit-transform: rotateY(80deg) translateZ(288px); } #carousel figure:nth-child(4) { -webkit-transform: rotateY(120deg) translateZ(288px); } #carousel figure:nth-child(5) { -webkit-transform: rotateY(160deg) translateZ(288px); } #carousel figure:nth-child(6) { -webkit-transform: rotateY(200deg) translateZ(288px); } #carousel figure:nth-child(7) { -webkit-transform: rotateY(240deg) translateZ(288px); } #carousel figure:nth-child(8) { -webkit-transform: rotateY(280deg) translateZ(288px); } #carousel figure:nth-child(9) { -webkit-transform: rotateY(320deg) translateZ(288px); }
若是咱們決定改變每一個面的寬度或面的數量,咱們只須要寫一個JS函數,改變兩個變量來獲取正確的translateZ值。
JavaScript
var tz = Math.round( ( panelSize / 2 ) / Math.tan( ( ( Math.PI * 2 ) / numberOfPanels ) / 2 ) ); // 或簡單點 var tz = Math.round( ( panelSize / 2 ) / Math.tan( Math.PI / numberOfPanels ) );
即使是狹義相對論,去找一集BBC看一遍,相信你也能知道是什麼東西,雖然不必定能明白背後運做的物理學定理。本文講述的是CSS3D各類變形函數基本用法,這些函數其實是對matrix3d()函數的封裝,而matrix3d()函數則牽扯到線性代數、立體幾何、三角學等的各類知識。將來的前端開發會變成什麼樣??