查看 webpack 官網文檔,一直以爲官網中間的這個旋轉的立方體很是契合webpack這款打包工具的理念。由一個大的立方體包圍一個小立方體,轉向卻相反。通過這樣的轉換後一推凌亂的文件就被打包成整齊的資源。css
動畫很是棒,簡潔形象。這也是給我留下深入印象的緣由。
再觀細節,立方體的外圍寬度明顯寬於其餘邊框,這增長了立方體的景深,配合內部的小立方體更顯逼真。html
這麼棒的效果,理應探究一下。哈哈哈哈?
成品圖在這裏html5
應用css的3D變換能夠輕易地在三維空間中製造出一個立方體,再應用rotateY()屬性,便呈現出一個旋轉的立方體。這是思路webpack
<span class="cube"> <figure class="cube_outer"> <section class="cube_face_outer">1</section> <section class="cube_face_outer">2</section> <section class="cube_face_outer">3</section> <section class="cube_face_outer">4</section> <section class="cube_face_outer">5</section> <section class="cube_face_outer">6</section> </figure> <figure class="cube_inner"> <section class="cube_face_inner">1</section> <section class="cube_face_inner">2</section> <section class="cube_face_inner">3</section> <section class="cube_face_inner">4</section> <section class="cube_face_inner">5</section> <section class="cube_face_inner">6</section> </figure> </span>
一共兩個立方體,都被包圍在span中。span元素看成立方體的container,用來固定裏面立方體的位置,併爲咱們設置俯視的角度。web
.cube { position: relative; display: block; transform-style: preserve-3d; transform: rotateX(-33.5deg) rotateY(45deg); width: 120px; margin: 100px auto; }
立方體被figure元素包圍,由於立方體是一個獨立的自包含元素,比起其它如div或span的標籤用figure標籤十分契合。裏面的六個面分爲六個部分,用section標籤也很是符合html5語義化的標準。
figure是立方體自己,它肯定立方體的大小及位置,併爲六個面提供3d環境設置。函數
.cube_outer { height: 120px; width: 120px; transform-style: preserve-3d; transition: transform 1s ease-out; display: inline-block; }
接下來是六個面的設置,把共用的樣式提取出來。工具
.cube_face_outer { background-color: rgba(141, 214, 249, 0.5); transition: border-width 0.2s ; position: absolute; width: 100%; height: 100%; border: 1px solid #fff; text-align: center; font-size: 36px; }
最後肯定六個面的位置了。六個面是相對於最外層的span來定位的。
如何把空間拉出來(提供面與面之間的距離)呢? translateZ()可使物體在垂直於平面的方向移動,進而拉出空間感,再經過rotateX()或rotateY()來把立方體組裝起來。動畫
/*1-6 前 下 上 左 右 後*/ .cube_face_outer:nth-child(1) { transform: translateZ(60px) rotateX(0); } .cube_face_outer:nth-child(2) { transform: translateZ(60px) rotateX(-90deg); } .cube_face_outer:nth-child(3) { transform: translateZ(60px) rotateX(90deg); } .cube_face_outer:nth-child(4) { transform:translateZ(60px) rotateY(-90deg); } .cube_face_outer:nth-child(5) { transform:translateZ(60px) rotateY(90deg); } .cube_face_outer:nth-child(6) { transform:translateZ(60px) rotateY(180deg); }
ok,依據上一步驟,咱們設置了translateZ(60px)來拉開面之間的空間,而後再設置 rotateX()、rotateY()來組裝立方體。但結果卻出乎意料,面與面之間並未拉開距離!!六個面通過旋轉交叉在了一塊兒,translateZ(60px)沒有把距離拉開。。spa
其實這是由於transform屬性按值的順序來執行轉換而致使的。對於每一個面咱們都先執行了translateZ(60px),而每一個面都是相對與同一個元素span來定位,就是致使先執行完translateZ(60px)後,每一個面實際上是疊加在一塊兒的,它們只是在垂直於平面的方向共同位移了60px而已,而後再執行rotateX、rotateY()便會出現六個面交叉的狀況。解決方案很簡單,由於transform按照值得順序來進行轉換,咱們只要先進行rotateX、rotateY()讓面在中心處擺出立方體的形狀,而後利用translateZ(60px)位移拉開距離就能夠了。3d
下一步就是實現旋轉了。咱們簡單地設置一個幀動畫。
@keyframes rot { 0% { transform: rotateY(0deg) } 10% { transform: rotateY(90deg) } 25% { transform: rotateY(90deg) } 35% { transform: rotateY(180deg) } 50% { transform: rotateY(180deg) } 60% { transform: rotateY(270deg) } 75% { transform: rotateY(270deg) } 85% { transform: rotateY(360deg) } 100% { transform: rotateY(360deg) } } /*爲立方體加上幀動畫*/ .cube_outer { animation:rot 8s ease-out 0s infinite forwards; }
爲了讓立方體在每轉過90deg後有停歇的效果,我設置每一個90deg總佔比例爲15%,這樣當立方體每旋轉90deg後就有15%的時間停留。基本達到了原效果。
精加工
上面的旋轉效果咱們經過keyframes來寫,靈活性不好,不容易調整每次旋轉90deg後的停留時間,邏輯較複雜的動畫應該交由JS控制。
我發現原圖在每次旋轉以後,立方體的外圍邊框線老是很粗,這在視覺上能體現出了很強的空間感,而個人立方體全部的邊框線都一致,空間感表現不好顯得沒那麼真實。
咱們發現正方體六個面中,只有位於一號面、三號面、四號面這三個面擁有較粗的邊框線,而二號面在下面不參與線的變化,五六面在旋轉中也參與邊框線的變化。咱們先無論三號面的變化,只看一四五六面的變化。
位置 | 1 | 4 | 5 | 6 |
---|---|---|---|---|
第一次旋轉 | 4 | 6 | 1 | 5 |
第二次旋轉 | 6 | 5 | 4 | 1 |
第三次旋轉 | 5 | 1 | 6 | 4 |
第四次旋轉 | 1 | 4 | 5 | 6 |
假設位於一四五六面所在的位置的面的邊框線一直不變--都是粗的,而當立方體旋轉時,面原來的位置發生改變。當第一次旋轉時,一號面的位置上變爲四號面;四號面的位置上變爲六號面;五號面的位置上變爲一號面;六號面的位置上變爲五號面。以此類推,當第四次旋轉時,全部面便回到了原來的位置上。
而咱們設置位於一號位置的面邊框線爲f1,四號位置邊框線爲f4,其他爲f。
const f1 = '1px 6px 6px 1px'; const f4 = '1px 1px 6px 6px'; const f = '1px';
取到各元素後,寫一個roate函數。在rotate函數中咱們不只要控制立方體的邊框線粗細,還要控制立方體的旋轉。
const cube_outer = document.querySelector('.cube_outer'); const deg = 90; let i = 0; //設置全局變量 i 來控制旋轉,沒旋轉一次 i 加 1,進而旋轉角度也增長 ${deg*i}deg function rotate() { i += 1; cube_outer.style.transform = `translateX(-50%) scale3d(1, 1, 1) rotateX(0deg) rotateY(${deg*i}deg) rotateZ(0deg)`; if (i%4 === 1) { //轉第一次 face[0].style.borderWidth = `${f}`; face[4].style.borderWidth = `${f}`; face[3].style.borderWidth = `${f1}`; face[5].style.borderWidth = `${f4}`; }else if (i%4 === 2) { //第二次 face[0].style.borderWidth = `${f}`; face[3].style.borderWidth = `${f}`; face[4].style.borderWidth = `${f4}`; face[5].style.borderWidth = `${f1}`; }else if (i%4 === 3) { //第三次 face[5].style.borderWidth = `${f}`; face[3].style.borderWidth = `${f}`; face[0].style.borderWidth = `${f4}`; face[4].style.borderWidth = `${f1}`; } else if (i%4 === 0) { //第四次歸位 face[4].style.borderWidth = `${f}`; face[5].style.borderWidth = `${f}`; face[0].style.borderWidth = `${f1}`; face[3].style.borderWidth = `${f4}`; } }
基本邏輯就是這樣,利用ES6的模板字符串給屬性賦值方便了不少,在控制檯中輸入 rotate(),觀察立方體的外圍寬度發現效果實現了。最後咱們須要把最上面的面--三號面集成進去。三號位置的面在第一次旋轉後borderWidth設爲f31,第二次旋轉設爲f32,第三次旋轉設爲f33,第四次旋轉設爲f34。
const f31 = '1px 6px 6px 1px'; const f32 = '1px 1px 6px 6px'; const f33 = '6px 1px 1px 6px'; const f34 = '6px 6px 1px 1px'; if (i%4 === 1) { //轉第一次 face[2].style.borderWidth = `${f31}`; }else if (i%4 === 2) { //第二次 face[2].style.borderWidth = `${f32}`; }else if (i%4 === 3) { //第三次 face[2].style.borderWidth = `${f33}`; } else if (i%4 === 0) { //第四次歸位 face[2].style.borderWidth = `${f34}`; }
和上一步代碼放到一塊兒,效果就實現了。而後再增長一個定時器。運行,哈哈哈,效果差很少了。固然裏面還有一個小正方體,小正方體和大正方體是一樣的,只是利用scale3d(0.5, 0.5, 0.5) 縮小至一半後放入,每次旋轉的角度爲${- deg*i}deg就ok了。
setInterval(function(){ rotate(); },4000);
總結
製做一個立方體很簡單,利用transform屬性實現面的搭建就能夠,但前提是要在父元素上設置transform-style爲 preserve-3d模式。transform屬性按值得順序執行,當有一堆translate時,每個值的順序應當考慮清楚。
製做一個立方體很簡單,但如何使其更加逼真,更加貼切地符合站點的內容纔是真正須要考慮的。若是對這個立方體我沒有進行精加工,那麼效果將相差十萬八千里,放上去也只會顯得蹩腳。。。最後ES6的模板字符串真的很好用啊,哈哈哈哈哈?