css3實踐之摩天輪式圖片輪播+3D正方體+3D標簽雲(perspective、transform-style、perspective-origin)


  本文主要通過摩天輪式圖片輪播的例子來講解與css3 3D有關的一些屬性。

  demo預覽

  1. 摩天輪式圖片輪播 (貌似沒兼容360 最好用chrome)
  2. 3D正方體chrome only
  3. 3D標簽雲(css3版 chrome only
  4. 3D標簽雲(js版 chrome only

前文回顧

  在前面的文章css3實踐之圖片輪播(Transform,Transition和Animation)中我們簡單地了解了css3旗下的transform、transition以及animation。回顧一下,transform主要是對元素進行拉伸、旋轉、移動等等操作,transition能使元素從一種樣式逐漸改變為另一種的效果,而animation能使元素依次進行n種樣式之間的變化。其實對我而言,感興趣的還是前兩者,畢竟做動畫不是css的強項。

  本文demo主要涉及css3的perspective、transform-style、perspective-origin屬性。

perspective、transform-style、perspective-origin

  前兩個屬性是css3下實現3d效果必不可少的,為什么這樣講,我們通過例子來說明。

  首先我們根據demo需要寫好基本的html文件,其中核心代碼截圖如下:

  html結構主要有三層,#stage->#container->.img。stage表示3d大舞台,里面可以包含很多的3d容器(container),而容器內則是需要向“觀眾"呈現的擁有3d效果的東西(demo里是圖片)。

  • perspective

  這里隆重推出perspective屬性,perspective可以解釋成視距,通俗講perspective值即視點(perspective-origin)到電腦屏幕的距離(z軸方向),值越小,用戶與3D空間Z平面距離越近。如果沒有設置perspective屬性,元素就不會擁有3D效果,仿佛是從很遠地方看到的一個視圖(可以聯想一下三視圖)。

    

  perspective有兩種書寫方式,第一種是寫在舞台上,第二種是寫在3d元素上,與transform的其他屬性寫在一起,代碼分別如下:

#stage {
  width: 805px;
  height: 600px;
  border: 1px solid;
  -webkit-perspective: 500px;
  -webkit-perspective-origin: 17% 50%;
}
img {
  position: absolute;
  top: 110px;
  -webkit-transform: perspective(600px) rotateY(45deg);
}

  第二種也就是使得每個3d元素都有視點(默認為元素中心),我覺得幾乎用不到,畢竟動畫特效都需要模擬人眼看到的結果,也就是一個視點。

  兩種方式對比可以猛戳張鑫旭寫的demo:猛戳這里 感謝作者~

  • perspective-origin

  與perspective關系密切的還有它的好兄弟perspective-origin,perspective解釋為視距,那么perspective-origin就是視點。perspective-origin屬性可空缺,默認為perspective-origin: 50% 50%,即從舞台(stage)中央看起(如果perspective屬性加在stage的話),而perspective-origin和perspective一般同時出現(即加在同一個元素的css下),具體取值方法可參考CSS3 transform-origin 屬性

  實例代碼可參考perspective實例代碼

  • transform-style

  transform-style和perspective一樣重要,二者缺一不可。其中flat值為默認值,表示所有子元素在2D平面呈現。preserve-3d表示所有子元素在3D空間中呈現。沿着X軸或Y軸方向旋轉該元素將導致位於正或負Z軸位置的子元素顯示在該元素的平面上,而不是它的前面或者后面。如果對一個元素設置了transform-style的值為preserve-3d,它表示不執行平展操作,他的所有子元素位於3D空間中。既然我們都說要實現3d效果了,一般取值當然是preserve-3d了!

  transform-style屬性需要設置在3d動畫元素的父元素中,並且高於任何嵌套的變形元素。實例代碼:

#container {
  position: absolute;
  width: 500px; 
  height: 500px;
  -webkit-transform-style: preserve-3d;
  -webkit-transition: all 2s ease-in-out;
}
  • backface-visibility

  顧名思義,就是決定元素旋轉背面是否可見。如下分別是有沒有將demo里的3d元素的backface-visibility屬性設置成hidden的結果:

    

  實例代碼(對應第二張圖):

img {
  position: absolute;
  top: 110px;
  -webkit-backface-visibility: hidden;
}

 

  小結:所以以后如果要寫3d效果的css元素,只要像demo一樣在html文件中寫好stage和container元素,然后在stage中加上perspective,再在container中加入transform-style:preserve-3d 基本就ok了。

關於摩天輪式圖片輪播

  先寫好#stage->#container->.img形式的html文件,加上perspective和transform-style屬性,9張圖片分享360度,可使每張圖片圍繞x軸旋轉40*i度角:

  然后每張圖片再設置translateZ的值,就會使得圖片分開來圍成圈:

var imgs = document.getElementsByTagName('img');
for(var i = 0; i <= 8; i++) {
  var deg = 40 * i;
  imgs[i].style.webkitTransform = ''
  + 'rotateX(' + deg + 'deg)' 
  + 'translateZ(' + 190 + 'px)'
  + 'scale(0.25,0.25)';
}

  最后再加上鼠標滾輪事件,每次滾動使得container元素整體繞x軸轉動指定角度就行了,當然轉動過程還需要transition的幫助:

var containerDeg = 0;
window.onmousewheel = document.onmousewheel = function(e) {
  containerDeg += e.wheelDelta / 15 ;
  document.getElementById('container').style.webkitTransform = 'rotateX(' + containerDeg + 'deg)' 
}

  有一點值得注意,就是原始圖片的中心和container的中心要一致,只需設置圖片(position:absolute)的left和top值就可以了。

  完整源代碼可參考:源碼請猛戳

關於3D正方體和3D標簽雲

  3D正方體和3D標簽雲(css3版)實現方式和圖片輪播相似,都是在源點繞x軸和y軸旋轉一定角度后,利用translateZ這個方法圍繞源點分散開去。

  • 3D正方體

  設置6個長寬一樣的div,然后分別繞x和y軸旋轉需要的角度后,設置相同的translateZ值(為了方便寫在js里了,也可以直接算出值寫在css里):

// init
var initAngleX = [0, 180, 90, 270, 0, 0];
var initAngleY = [0, 0, 0, 0, 90, 270];
var angleX = 0;
var angleY = 0;
// container的旋轉角度
var totalAngleX = 0;
var totalAngleY = 0;

for(var i = 0; i < 6; i++) {
  var d = document.createElement('div');
  d.style.backgroundColor = '#' + ('00000' + parseInt(Math.random() * 0xffffff).toString(16)).slice(-6);
  d.className = 'face';
  d.style.webkitTransform = ''
    + 'rotateX(' + initAngleX[i] + 'deg)' 
    + 'rotateY(' + initAngleY[i] + 'deg)' 
    + 'translateZ(' + 50 + 'px)';
  document.getElementById('container').appendChild(d);
}

  然后為了效果添加旋轉,這里直接設置setInterval函數改變整個container的旋轉角度了:

// addListener
document.getElementById('container').addEventListener("mousemove" , function(event){
  var x = event.clientX - 200;
  var y = event.clientY - 200;
  window.angleY =  x / 10 / 1000 * 60;
  window.angleX = -y / 10 / 1000 * 60;
});
 
setInterval(function() {
  totalAngleX += angleX;
  totalAngleY += angleY;
  document.getElementById('container').style.webkitTransform = ''
    + 'rotateX(' + totalAngleX + 'deg)' 
    + 'rotateY(' + totalAngleY + 'deg)';
}, 1000 / 60);

  你也可以將效果直接寫在css上,比如設置個偽類(:hover),里面寫好改變的css,然后設置下transition就ok了。

  • 3D標簽雲

  做了兩個版本的,js版和css3版,不過其實都要用到js,只是后者的核心是css3。

  先來回顧一下js版本,或許js版本更適合實際使用,確實如此,現實中類似的3d標簽雲基本上都是js實現的。js版本的核心是獲取平均分配在一個球面上的n個點的3維坐標,然后將z軸扁平化降到二維進行繪制,球體旋轉時獲得新的坐標進行重繪,demo中則是進行a標簽新的位置確定。如需了解更多可參考我以前寫的文章《rotate 3d基礎

  js版本里扁平化中的“焦距”(focalLength)就是css3里的perspective。

  js版z軸扁平化代碼:

focalLength = 300;
var scale = focalLength / (focalLength + this.pos3.z);
this.pos2.x = 150 + this.pos3.x * scale;
this.pos2.y = 150 + this.pos3.y * scale;
this.a.style.fontSize = 12 * scale;
this.a.style.color = 'rgba('+this.r+','+this.g+','+this.b+','+ Math.min(1, scale)+')';

  pos3是3d空間的位置,而pos2是2d的位置,利用的是三角形相似(近大遠小):

  屏幕位置和成像位置的距離就是3d物體的z值大小。

  而css3版本的則不然,省去了繁瑣的3d->2d轉換過程,a標簽直接能進行3d變化。只是元素在進行旋轉過程中,a標簽內的文字也無法控制地旋轉。

  具體就不展開了,有興趣的可以參考源碼:猛戳這里

  以前用js寫過的3d特效(猛戳demo1 demo2 demo3),其實也可以用css3實現,核心的函數就是rotate和translate!有興趣的可以試一試。

總結

  總的來說,如果要使dom元素呈現3d效果,perspective和transform-style屬性的設置是必不可少的。

  因為上面一篇文章有園友反映沒做兼容,本文的圖片輪播demo我還特地做了兼容(ff下的渲染真是渣...),但是還是沒能兼容360,也不知道什么原因,反正做兼容很蛋疼就是了,以后還是有需求的時候再做兼容吧...

  樓主對以上理解尚不深入,如有問題歡迎交流指導。

  參考文章:

  1. Transform-style和Perspective屬性
  2. 好吧,CSS3 3D transform變換,不過如此!
  3. 理解:translate rotate 與 perspective 曖昧關系


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM