3D轉換立方體搭建

查看 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%的時間停留。基本達到了原效果。


精加工

  1. 上面的旋轉效果咱們經過keyframes來寫,靈活性不好,不容易調整每次旋轉90deg後的停留時間,邏輯較複雜的動畫應該交由JS控制。

  2. 我發現原圖在每次旋轉以後,立方體的外圍邊框線老是很粗,這在視覺上能體現出了很強的空間感,而個人立方體全部的邊框線都一致,空間感表現不好顯得沒那麼真實。

咱們發現正方體六個面中,只有位於一號面、三號面、四號面這三個面擁有較粗的邊框線,而二號面在下面不參與線的變化,五六面在旋轉中也參與邊框線的變化。咱們先無論三號面的變化,只看一四五六面的變化。

位置 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);

總結

  1. 製做一個立方體很簡單,利用transform屬性實現面的搭建就能夠,但前提是要在父元素上設置transform-style爲 preserve-3d模式。transform屬性按值得順序執行,當有一堆translate時,每個值的順序應當考慮清楚。

  2. 製做一個立方體很簡單,但如何使其更加逼真,更加貼切地符合站點的內容纔是真正須要考慮的。若是對這個立方體我沒有進行精加工,那麼效果將相差十萬八千里,放上去也只會顯得蹩腳。。。最後ES6的模板字符串真的很好用啊,哈哈哈哈哈?

相關文章
相關標籤/搜索