像這種比較規(guī)則的圖形還能簡(jiǎn)單通過(guò)CSS應(yīng)付一下,如果有一些不規(guī)則的,或者有曲面,那就不太好實(shí)現(xiàn)了,而且高光也無(wú)法真正模擬出來(lái),像這種情況還是建議通過(guò)Three.js這樣專業(yè)的圖形處理庫(kù)才行。
嘗試一下用 CSS 繪制簡(jiǎn)單的 3d 圖形,比如一個(gè)掘金 logo?

相比 2d 繪制,3d 有哪些需要注意的小細(xì)節(jié)呢?一起看看吧
一、金字塔形/四棱錐形
除去挖空部分,整個(gè)外形其實(shí)是一個(gè)金字塔形,或者叫四棱錐形(四角錐)。

一共有5個(gè)面,所以我們可以準(zhǔn)備5個(gè)元素。
<juejin>
<pane a></pane>
<pane b></pane>
<pane c></pane>
<pane d></pane>
<bottom></bottom>
</juejin>
其中,bottom表示底部的正方形,其余4個(gè)表示側(cè)面4個(gè)三角形。
首先先從正方體開始。
注意,需要呈現(xiàn) 3d 視覺(jué),需要添加transform-style: preserve-3d,先繪制一個(gè)側(cè)面。
juejin{
--s: 200px;
position: relative;
width: var(--s);
height: var(--s);
transform-style: preserve-3d;
perspective: 3000px;
transform: rotateX(calc( .3 * -90deg)) rotateY(calc( .1 * 90deg));
}
pane{
position: absolute;
inset: 13.3% 0 0;
transform-origin: center bottom;
}
pane[a]{
background-color: #368dff;
transform: translate3d(0, 0, calc(var(--s) * -0.5));
}
效果如下:

用同樣的方式,繪制出4個(gè)側(cè)面。
pane[b]{
background-color: #368dff;
transform: translate3d(0, 0, calc(var(--s) * 0.5));
}
pane[c]{
background-color: #1e80ff;
transform: translate3d(calc(var(--s) * -0.5), 0, 0) rotateY(90deg);
}
pane[d]{
background-color: #1e80ff;
transform: translate3d(calc(var(--s) * 0.5), 0, 0) rotateY(90deg);
}
效果如下:

然后,將4個(gè)側(cè)面裁剪成三角形,用clip-path就行了。
pane{
/**/
clip-path: polygon(50% 0, 100% 100%, 0 100%);
}
效果如下:

最后,將4個(gè)側(cè)面沿著底部旋轉(zhuǎn)一個(gè)角度,使其合并在一起,由于大小完全一樣,底部又是正方形,傾斜角度自然也相同,這里就不通過(guò)數(shù)學(xué)計(jì)算了,直接用一個(gè) CSS 變量去實(shí)時(shí)比對(duì)。
juejin{
/**/
--deg: 35.3deg;
}
pane[a]{
/**/
transform: translate3d(0, 0, calc(var(--s) * -0.5)) rotateX(calc(var(--deg) * -1));
}
pane[b]{
/**/
transform: translate3d(0, 0, calc(var(--s) * 0.5)) rotateX(var(--deg));
}
pane[c]{
/**/
transform: translate3d(calc(var(--s) * -0.5), 0, 0) rotateY(90deg) rotateX(calc(var(--deg) * -1));
}
pane[d]{
/**/
transform: translate3d(calc(var(--s) * 0.5), 0, 0) rotateY(90deg) rotateX(var(--deg));
}
效果如下:

這樣就得到了一個(gè)金字塔形/四棱錐形。

二、側(cè)邊鏤空和橫截面處理
前面得到了一個(gè)完整的四棱錐,現(xiàn)在需要先將側(cè)面鏤空。
這里有兩種方式,第一,可以用透明和不透明的漸變填充,這樣透明的部分就是鏤空的了;還有一種方式,用??mask?
?遮罩,也能輕易的實(shí)現(xiàn)。
pane{
/* */
-webkit-mask: linear-gradient(to bottom, red 50%, transparent 0) 0 0/ 100% 40%;
}
效果如下:

但是現(xiàn)在還是看著像紙片一樣,需要將截?cái)嗟膸讉€(gè)面都封起來(lái),我們?cè)偌右粋€(gè)標(biāo)簽,用兩個(gè)偽元素將頂部覆蓋。
<juejin>
<!-- -->
<top></top>
</juejin>
top{
position: absolute;
inset: 0;
background-color: #1677f7;
transform: translate3d(0, calc(var(--s) * 0.36), 0) rotateX(90deg) scale(.8);
transform-style: preserve-3d;
box-shadow: inset 0 0 calc(var(--s) * 0.3) rgb(255 255 255 / 45%);
}
top::before{
content: '';
position: absolute;
inset: 0;
background-color: inherit;
transform: translate3d(0, 0, calc(var(--s) * 0.285)) scale(.5);
box-shadow: inherit;
}
當(dāng)然,這里需要多多調(diào)整一下細(xì)節(jié),確保橫截面的大小和位置剛好吻合。

同樣還有底部的截面。
bottom::before,
bottom::after{
content: '';
position: absolute;
inset: 0;
background-color: inherit;
transform: translate3d(0, 0, calc(var(--s) * 0.285)) scale(.595);
box-shadow: inherit;
}
bottom::after{
transform: translate3d(0, 0, calc(var(--s) * 0.568)) scale(.195)
}
效果如下:

三、其他光影細(xì)節(jié)和鼠標(biāo)跟隨效果
首先是底部的投影,這是通過(guò)??filter: blur?
?實(shí)現(xiàn)的,可以讓整個(gè)場(chǎng)景更具空間感。
juejin::after{
position: absolute;
content: '';
width: var(--s);
height: var(--s);
top: 80%;
background-color: rgba(0, 0, 0, 0.1);
transform: rotateX(90deg) scale(1.2);
filter: blur(20px);
}

然后是截面的高光處理,這里是通過(guò)內(nèi)陰影實(shí)現(xiàn)的,讓整體光影看著更加自然,就像上方有光線一樣
top{
/**/
box-shadow: inset 0 0 calc(var(--s) * 0.3) rgb(255 255 255 / 45%);
}

最后是鼠標(biāo)跟隨效果,這里是通過(guò) CSS 變量實(shí)現(xiàn)的,通過(guò) JS 獲取鼠標(biāo)的相對(duì)位置,然后通過(guò) CSS 變量 傳遞,實(shí)時(shí)改變 transform 的旋轉(zhuǎn)角度。
juejin{
/* */
transform: rotateX(calc( (var(--y) - 0.3) * -90deg)) rotateY(calc( (var(--x) - 0.3) * 90deg));
}
JS 監(jiān)聽mousemove就可以了。
document.body.addEventListener('mousemove', function(ev){
document.body.style.setProperty('--x', ev.clientX / document.body.offsetWidth)
document.body.style.setProperty('--y', ev.clientY / document.body.offsetHeight)
})
這樣就得到了文章開頭所示效果:

四、總結(jié)一下
總的來(lái)說(shuō),繪制這樣一個(gè)的 3d 圖形還是比較輕松的,下面總結(jié)一下
- 添加transform-style: preserve-3d才能呈現(xiàn) 3d 視覺(jué)。
- 掘金 logo 整體上是一個(gè)金字塔形,或者叫四棱錐形(四角錐)。
- 整個(gè)繪制就是通過(guò)translate3d、rotate3d等基礎(chǔ)操作組合而成。
- 鏤空部分可以通過(guò)漸變填充,或者mask遮罩實(shí)現(xiàn)。
- 橫截面需要多多調(diào)整一下細(xì)節(jié),確保橫截面的大小和位置剛好吻合。
- 為了讓整個(gè)模型更加真實(shí),需要添加合理的高光和投影。
- 鼠標(biāo)跟隨效果可以通過(guò) CSS 變量傳遞實(shí)現(xiàn)。
當(dāng)然,像這種比較規(guī)則的圖形還能簡(jiǎn)單通過(guò)CSS應(yīng)付一下,如果有一些不規(guī)則的,或者有曲面,那就不太好實(shí)現(xiàn)了,而且高光也無(wú)法真正模擬出來(lái),像這種情況還是建議通過(guò)three.js這樣專業(yè)的圖形處理庫(kù)才行。