【面試題】如何用 CSS 畫一個正方體

最近在 http://algoexpert.io/ 上看到一個非常好玩的東西。

剛開始的時候,我還要以爲要用到什麼 JS 庫來實現的,打開控制檯研究了一下,原來用 CSS 就可以實現了,好吧,算我孤陋寡聞了,哈哈。於是,寫篇博客記錄一下吧。

6 個面

首先,在 HTML 弄 6 個面。

<div class="cube-container">
  <div class="cube-faces">
    <div class="cube-face cube-face-front">
      <img src="https://yanhaixiang.com/cube/images/js.png" alt="js">
    </div>
    <div class="cube-face cube-face-back">
      <img src="https://yanhaixiang.com/cube/images/python.png" alt="python">
    </div>
    <div class="cube-face cube-face-top">
      &nbsp;
    </div>
    <div class="cube-face cube-face-bottom">
      &nbsp;
    </div>
    <div class="cube-face cube-face-left">
      <img src="https://yanhaixiang.com/cube/images/golang.png" alt="golang">
    </div>
    <div class="cube-face cube-face-right">
      <img src="https://yanhaixiang.com/cube/images/cpp.png" alt="cpp">
    </div>
  </div>
</div>

非常簡單,container 作爲正方體容器,cube-faces 作爲 6 個面的容器,剩下的 div 就是 6 個面,裏面放一個 img。

效果就是一列排下來:

集合 6 個面

第二步,就是將這 6 個面堆疊在一起。很簡單,只要 .cube-faces 設置 position: relative,然後 .cube-face 設置 position: absolute 就可以使得 6 個面都脫離文檔流疊在一起了。

.cube-faces {
  position: relative;
  width: 300px;
}

.cube-face {
  position: absolute;
  height: 300px;
  width: 300px;
  outline: 1px solid #02203c;
  box-shadow: inset 0 0 100px #02203c;
  background-color: #3e526a;
  opacity: 0.75;
}

.cube-face img {
  width: 100%;
  height: 100%;
}

旋轉平面

現在還是一個平面結構,下面將這 6 個面通過 transform: rotate 來做旋轉使得其像個正方體。

.cube-face.cube-face-front {
  transform: translateZ(150px);
}

.cube-face.cube-face-back {
  transform: translateZ(-150px) rotateY(180deg);
}

.cube-face.cube-face-top {
  transform: rotateX(-90deg) translateY(-150px);
  transform-origin: top center;
}

.cube-face.cube-face-bottom {
  transform: rotateX(90deg) translateY(150px);
  transform-origin: bottom center;
}

.cube-face.cube-face-left {
  transform: rotateY(270deg) translateX(-150px);
  transform-origin: left center;
}

.cube-face.cube-face-right {
  transform: rotateY(-270deg) translateX(150px);
  transform-origin: top right;
}

很遺憾,出來的效果還是一個“平面”。

首先,這 6 個面其實已經轉成了正方體了,但是因爲我們目光只朝着一個面看,所以看起來還是二維的。但是也不對呀,如果已經變成立方體,那我們看到的應該是 JS 這一面而不是 Python 這面呀,Python 不是旋轉到後面了麼?

雖然 Python 是作爲後背面,但是在 HTML 裏,python 的 div 在 JS 的 div 之後,所以優先顯示 Python。

爲了去掉 HTML 的順序影響,可以在 .cube-faces 添加:

.cube-faces {
  position: relative;
  width: 300px;
  transform-style: preserve-3d; /* 3D */
}

現在立方體的 JS 面就朝着我們來了:

立起來

下面隆重介紹 CSS 的 perspective 屬性,可以把它理解爲我們的目光放在哪裏。剛剛說到,我們看到二維面是因爲我們目光死死盯着一個面,所以我們只需要將目光往上擡一下,從上往下看整個立方體,立方體就“立體”起來了。

/*將立方體放中間*/
body {
  display: flex;
  align-items: center;
  justify-content: center;
}

.cube-container {
  margin-top: 200px;
  perspective: 800px; /* 目光延長線 */
  perspective-origin: 50% 100px; /* 目光位置水平居中,往上擡 100px */
}

開始有那味了。

轉起來

下一步,爲了讓立方體有動感一點,定義一個 @keyframes 動畫:

@keyframes spin { /* Y軸旋轉 */
  0% {
    transform: rotateY(0);
  }
  100% {
    transform: rotateY(360deg);
  }
}

.cube-faces {
  position: relative;
  width: 300px;
  transform-style: preserve-3d;
  animation: spin 10s infinite linear; /*動畫*/
}

加點陰影

現在的立方體已經很立體了,但是總感覺很假的樣子,這是因爲缺少陰影的原因。我們要以在底部那個 div 加點小陰影:

.cube-face.cube-face-bottom {
  transform: rotateX(90deg) translateY(150px);
  transform-origin: bottom center;
  box-shadow: 0 0 100px #000; /*陰影*/
}

大功告成!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章