本文主要經過摩天輪式圖片輪播的例子來說解與css3 3D有關的一些屬性。javascript
demo預覽:css
在前面的文章css3實踐之圖片輪播(Transform,Transition和Animation)中咱們簡單地瞭解了css3旗下的transform、transition以及animation。回顧一下,transform主要是對元素進行拉伸、旋轉、移動等等操做,transition能使元素從一種樣式逐漸改變爲另外一種的效果,而animation能使元素依次進行n種樣式之間的變化。其實對我而言,感興趣的仍是前二者,畢竟作動畫不是css的強項。html
本文demo主要涉及css3的perspective、transform-style、perspective-origin屬性。java
前兩個屬性是css3下實現3d效果必不可少的,爲何這樣講,咱們經過例子來講明。css3
首先咱們根據demo須要寫好基本的html文件,其中核心代碼截圖以下:git
html結構主要有三層,#stage->#container->.img。stage表示3d大舞臺,裏面能夠包含不少的3d容器(container),而容器內則是須要向「觀衆"呈現的擁有3d效果的東西(demo裏是圖片)。github
這裏隆重推出perspective屬性,perspective能夠解釋成視距,通俗講perspective值即視點(perspective-origin)到電腦屏幕的距離(z軸方向),值越小,用戶與3D空間Z平面距離越近。若是沒有設置perspective屬性,元素就不會擁有3D效果,彷彿是從很遠地方看到的一個視圖(能夠聯想一下三視圖)。web
perspective有兩種書寫方式,第一種是寫在舞臺上,第二種是寫在3d元素上,與transform的其餘屬性寫在一塊兒,代碼分別以下:chrome
#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元素都有視點(默認爲元素中心),我以爲幾乎用不到,畢竟動畫特效都須要模擬人眼看到的結果,也就是一個視點。app
兩種方式對比能夠猛戳張鑫旭寫的demo:猛戳這裏 感謝做者~
與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和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; }
顧名思義,就是決定元素旋轉背面是否可見。以下分別是有沒有將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標籤雲(css3版)實現方式和圖片輪播類似,都是在源點繞x軸和y軸旋轉必定角度後,利用translateZ這個方法圍繞源點分散開去。
設置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了。
作了兩個版本的,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,也不知道什麼緣由,反正作兼容很蛋疼就是了,之後仍是有需求的時候再作兼容吧...
樓主對以上理解尚不深刻,若有問題歡迎交流指導。
參考文章: