CSS3 3D笨蛋教程

英文原文An Introduction to CSS 3-D Transformscss

愛因斯坦說全部概念都必須介紹給兒童們,若他們沒法瞭解,這些理論就毫無價值。html

透視

一個元素須要一個透視點才能激活3D空間,有兩種方法能夠獲得透視點:前端

  1. 使用transform屬性,賦上perspective函數做爲值。-webkit-transform: perspective(600);
  2. 或使用perspective屬性。-webkit-perspective: 600;

左邊是使用transform屬性的,右邊使用perspective屬性web

這兩種方法都能觸發3D空間,但卻有所不一樣。首先,使用函數方式能夠方便快捷地對單一元素應用3D變形,可是當你要應用在多個元素上時,它們可能不會按照預期的效果排列。若是你使用一樣的transform屬性應用在多個不一樣位置的元素上,每一個元素都有本身的消失點。爲了不這種滑稽的效果,使用perspective屬性應用在它們的父容器元素上,這樣每一個元素都共享了同一個消失點。瀏覽器

左邊是使用transform屬性的,右邊使用perspective屬性函數

perspective屬性的值決定了3D效果的強度。佈局

你拿一本書平放在面前,看着書感覺一下透視感,perspective屬性值就是眼睛和書之間的距離,距離越遠,數值越大,透視感越小;距離越近,數值越小,透視感越強。動畫

默認狀況下,3D空間的消失點位於空間的正中央,你能夠經過perspective-origin屬性改變消失點的位置。設計

CSS3d

-webkit-perspective-origin: 25% 75%;

3D變形函數

做爲一個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以後。順序對於變形函數來講是很重要的,請花一些時間消化這句話。每個面要先旋轉到正確的朝向,而後沿着各自的朝向向外平移。

如今咱們的立方體看起來能用了,但還沒完成。

回到Z軸源點

對於使用者,咱們的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()函數則牽扯到線性代數、立體幾何、三角學等的各類知識。將來的前端開發會變成什麼樣??

相關文章
相關標籤/搜索