本文主要通過摩天輪式圖片輪播的例子來講解與css3 3D有關的一些屬性。
demo預覽:
前文回顧
在前面的文章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,也不知道什么原因,反正做兼容很蛋疼就是了,以后還是有需求的時候再做兼容吧...
樓主對以上理解尚不深入,如有問題歡迎交流指導。
參考文章: