Intro to CSS 3D transforms

原文地址:Intro to CSS 3D transforms,本文只是翻譯了其中的一部分,省去了做者寫文章的緣由瀏覽器兼容部分(已通過時)
css

Perspective

元素須要設置須要設置perspective來激活3D效果,能夠經過兩種方式實現html

  • 在transform屬性中使用perspective方法html5

    transform: perspective( 600px );
  • 直接使用perspective屬性css3

    perspective: 600px;

NOTE:出於代碼簡介的目的,demo中的CSS樣式沒有使用瀏覽器前綴,在實際使用中須要使用-webkit-perspective, -moz-perspective, 等git

<style>
    .container {
        width: 200px;
        height: 200px;
        border: 1px solid #CCC;
        margin: 0 auto 40px;
    }
    .box {
        width: 100%;
        height: 100%;
    }
    #red1 .box {
      background-color: red;
      transform: perspective( 600px ) rotateY( 45deg );
    }
</style>
<section id="red1" class="container">
    <div class="box red"></div>
</section>

 

<style>
    #blue1{
        perspective: 600px;
    }
    #blue1 .box {
      background-color: blue;
      transform: rotateY( 45deg );
    }
</style>

<section id="blue1" class="container">
    <div class="box blue1"></div>
</section>

 

這兩種方式都會觸發3D效果,可是有一點不一樣:第一種方式直接在一個元素上觸發3D變形,可是當多個元素的時候變形效果和預期會有所不一樣,若是使用一樣的方法做用於不一樣位置的元素的時候,每一個元素會有本身的軸心,爲了解決這個問題,須要在父元素使用perspective屬性,這樣每一個子元素都共享相同的3D空間github

<style>
    #red2 figure {
      background: red;
      transform: perspective( 400px ) rotateY(45deg);
    }
    .container figure {
        display: block;
        width: 55px;
        height: 55px;
        float: left;
        margin: 5px;
    }

    #red2 figure {
        background: #F00;
        -webkit-transform: perspective( 400px ) rotateY( 45deg );
        -moz-transform: perspective( 400px ) rotateY( 45deg );
        -o-transform: perspective( 400px ) rotateY( 45deg );
        transform: perspective( 400px ) rotateY( 45deg );
    }
</style>
<section id="red2" class="container">
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
</section>

 

<style>
    #blue2 {
      perspective: 400px;
    }

    #blue2 figure {
      background: blue;
      transform: rotateY( 45deg );
    }
</style>
<section id="blue2" class="container">
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
    <figure></figure>
</section>

 

perspective屬性的值決定了3D效果的強烈程度,能夠認爲是觀察者到頁面的距離。值越大距離越遠,視覺上的3D效果就會相應的減弱。perspective: 2000px; 會產生一個好像咱們使用望遠鏡看遠方物體的3D效果,perspective: 100px;會產生一個小昆蟲看大象的效果。web

3D效果默認軸心是元素中央,能夠經過perspective-origin來修改軸心瀏覽器

perspective-origin: 25% 75%;

點擊這裏看一下做者寫的一個有意思的立方體旋轉頁面ide

3D變形方法

做爲一個web者,可能很熟悉兩個方向:X & Y,表示元素的水平方向和垂直方向,在perspective激活的3D空間中咱們能夠在X、Y、Z三個座標軸上對元素進行變形處理。3D變形使用的變形方法和2D變形同樣,若是熟悉2D變形方法很容易掌握3D變形函數

  • rotateX( angle )
  • rotateY( angle )
  • rotateZ( angle )
  • translateZ( tz )
  • scaleZ( sz )

translateX()方法使元素延X軸移動,translateZ()使元素延Z軸(在3D空間中方向從前到後)移動。正值使元素離觀察者更近,負值使元素變遠。

translateZ( -200px )


translateZ( 200px )


rotateX( 45deg )


rotateY( 45deg )


rotateZ( 45deg )

有幾個變形方法的縮寫,這些方法須要把三個參數寫全

  • translate3d( tx, ty, tz )
  • scale3d( sx, sy, sz )
  • rotate3d( rx, ry, rz, angle )

Pro-tip: fn3d()變形方法能夠觸發硬件加速HTML5 buzzwords in action

任意3D操做會觸發硬件加速,甚至可能變形只用到了2D的,或者沒有作任何事情(好比translate3d(0,0,0))。須要注意的是這只是當前的表現,將來可能變化(這也是爲何咱們沒有寫文檔或者鼓勵這麼作),可是這在不少場景下很是有用,能夠顯著的提升渲染性能

立方體

建立六個面

<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>

爲6個面設置基本的位置和尺寸樣式

.container {
  width: 200px;
  height: 200px;
  position: relative;
  perspective: 1000px;
}

#cube {
  width: 100%;
  height: 100%;
  position: absolute;
  transform-style: preserve-3d;
}

#cube figure {
  width: 196px;
  height: 196px;
  display: block;
  position: absolute;
  border: 2px solid black;
}

一、2是先後面,三、4是左右,五、6是上下

#cube .front  { transform: rotateY(   0deg ); }
#cube .back   { transform: rotateX( 180deg ); }
#cube .right  { transform: rotateY(  90deg ); }
#cube .left   { transform: rotateY( -90deg ); }
#cube .top    { transform: rotateX(  90deg ); }
#cube .bottom { transform: rotateX( -90deg ); }

咱們能夠移除#cube .front樣式聲明,只用前面是可見的,上、下、左、右面與視角平行,因此看不到。須要從中心位置移動它們才能夠看獲得,每一個面都是200px寬,每一個面都須要從立方體中心移動100px;

#cube .front  { transform: rotateY(   0deg ) translateZ( 100px ); }
#cube .back   { transform: rotateX( 180deg ) translateZ( 100px ); }
#cube .right  { transform: rotateY(  90deg ) translateZ( 100px ); }
#cube .left   { transform: rotateY( -90deg ) translateZ( 100px ); }
#cube .top    { transform: rotateX(  90deg ) translateZ( 100px ); }
#cube .bottom { transform: rotateX( -90deg ) translateZ( 100px ); }

須要注意的是translateZ方法在rotate方法以後,變形方法的順序很重要,吸取一下子屌絲們,每面都先按本身的方向旋轉,而後向外移動一個向量。

爲了用戶看清楚,咱們的3D變形不該該在扭曲不是active的面,可是咱們延Z軸移動的時候,這種狀況就難以免。爲了保持3D變形的瞬間,Safari先組合元素,而後再應用變形,所以文本會保持變形以前的樣式,在3D變形中常常會出現顯著的像素變化

font-size: 2.5em


transform: scale(2.5);


transform: perspective(1200) translateZ(700px);

經過以前例子能夠發現不管perspective的值多小,或者變形的軸心在哪裏,面1永遠回到初始位置,好像3D變形對它沒影響

爲了解決變形和像素保留問題,咱們能夠向後推一下3D對象,這樣前面就會Z軸後移

#cube { transform: translateZ( -100px ); }

爲了顯示每一個面,咱們須要一個旋轉立方體的樣式,變形和當前面的方向相反,咱們在#box 上切換必要的類來應用變形

#cube.show-front  { transform: translateZ( -100px ) rotateY(    0deg ); }
#cube.show-back   { transform: translateZ( -100px ) rotateX( -180deg ); }
#cube.show-right  { transform: translateZ( -100px ) rotateY(  -90deg ); }
#cube.show-left   { transform: translateZ( -100px ) rotateY(   90deg ); }
#cube.show-top    { transform: translateZ( -100px ) rotateX(  -90deg ); }
#cube.show-bottom { transform: translateZ( -100px ) rotateX(   90deg ); }

須要注意變形方法的順序變了,咱們先向後推元素,而後再旋轉,再添加transition屬性就完成了

#cube { transition: transform 1s; }

效果demo

旋轉木馬

和建立立方體相似,咱們建立一個9個面的旋轉木馬

<section 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>
</section>

如今應用一下基本的佈局樣式,給每一個#carousel子元素面板20px的間距,這樣每一個面板的空間爲210px

.container {
  width: 210px;
  height: 140px;
  position: relative;
  perspective: 1000px;
}

#carousel {
  width: 100%;
  height: 100%;
  position: absolute;
  transform-style: preserve-3d;
}

#carousel figure {
  display: block;
  position: absolute;
  width: 186px;
  height: 116px;
  left: 10px;
  top: 10px;
  border: 2px solid black;
}

下一步須要旋轉每一個面,9個面板,若是等分的話每一個面板須要旋轉40deg相對下一個

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

如今外移元素,咱們須要計算外移的距離,畫一個草圖,咱們發現只有兩個已知數:每一個面板的寬度是210px,每一個面板相對下一個旋轉了40deg。拿出任意一個三角形都是右邊的樣子

咱們能夠經過正切函數算出r

image

這樣咱們就知道知道須要移動288px

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

若是須要改變面板的寬度或者數量,咱們只須要應用一下公式就能夠了,在JavaScript中

var tz = Math.round( ( panelSize / 2 ) / 
  Math.tan( ( ( Math.PI * 2 ) / numberOfPanels ) / 2 ) );
// or simplified to
var tz = Math.round( ( panelSize / 2 ) / 
  Math.tan( Math.PI / numberOfPanels ) );

最後咱們須要再旋轉木立刻應用些變形

transform: translateZ( -288px ) rotateY( -160deg );

JS Bin

相關文章
相關標籤/搜索