试试用CSS画一个简单的3d图形,比如掘金队队徽?与2d绘图相比,3d绘图需要注意哪些小细节?让我们一起来看看1.Pyramid/金字塔形状除了镂空的部分,整个形状其实是一个金字塔形状,或者叫金字塔(Pyramid)。一共有5张面,所以我们可以准备5个元素。其中,bottom表示底部的正方形,剩下的4个代表边上的4个三角形。首先从一个立方体开始。注意,要呈现3D视觉,需要加上transform-style:preserve-3d,先画一个边。觉进{--s:200px;位置:相对;宽度:var(--s);高度:变量(--s);变换样式:保留3d;视角:3000px;变换:rotateX(calc(.3*-90deg))rotateY(calc(.1*90deg));}pane{position:absolute;插图:13.3%00;transform-origin:centerbottom;}pane[a]{背景色:#368dff;transform:translate3d(0,0,calc(var(--s)*-0.5));}效果如下:用同样的方法绘制4条边。pane[b]{背景颜色:#368dff;转换:translate3d(0,0,calc(var(--s)*0.5));}pane[c]{background-color:#1e80ff;转换: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条边切割成三角形,使用clip-path。pane{/**/clip-path:polygon(50%0,100%100%,0100%);}效果如下:最后将4条边沿底部旋转一定角度,使之合并在一起,因为大小一模一样,底是方的,倾斜的角度自然是一样的。这里没有进行数学计算,而是直接使用一个CSS变量进行实时比较。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));}效果如下如下:刚刚得到一个金字塔形状/方形金字塔形状。2、侧面镂空和截面处理我们之前已经得到了一个完整的四角锥,现在需要先将侧面镂空。这里有两种方式。首先,可以用透明和不透明的渐变填充,让透明的部分被挖空;还有一种方法,使用mask,也很容易实现。pane{/**/-webkit-mask:linear-gradient(tobottom,red50%,transparent0)00/100%40%;}效果如下:但是现在看起来还是一张纸并且需要截断所有边都密封,让我们添加另一个标签并用两个伪元素覆盖顶部。top{position:absolute;插图:0;背景色:#1677f7;变换:translate3d(0,calc(var(--s)*0.36),0)rotateX(90deg)scale(.8);变换样式:保留3d;box-shadow:inset00calc(var(--s)*0.3)rgb(255255255/45%);}top::before{content:'';位置:绝对;插图:0;背景色:继承;转换:translate3d(0,0,calc(var(--s)*0.285))scale(.5);box-shadow:inherit;}当然,这里需要稍微调整一下以确保横截面的大小和位置恰到好处。还有一个底部部分。底部::之前,底部::之后{内容:'';位置:绝对;插图:0;背景色:继承;转换: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)}效果如下:3.其他光影细节和鼠标跟随效果首先是底部投影,通过filter:blur实现,可以让整个场景更有空间感。juejin::after{位置:绝对;内容:'';宽度:var(--s);高度:变量(--s);顶部:80%;背景色:rgba(0,0,0,0.1);变换:旋转X(90度)比例(1.2);filter:blur(20px);}然后是section的高光处理,这里是通过内阴影来实现的,这样整体的光影看起来更自然,就像上面有光一样{/**/box-shadow:inset00calc(var(--s)*0.3)rgb(255255255/45%);}最后是鼠标跟随效果,这里是通过CSS变量实现的,通过JS获取相对位置鼠标的旋转角度,然后通过css变量传递,实时改变transform的旋转角度。juejin{/**/transform:rotateX(calc((var(--y)-0.3)*-90deg))rotateY(calc((var(--x)-0.3)*90deg));}JS监听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)})这样就得到了文章开头所示的效果:4.总结一般来说,画这样的3D图形还是比较容易的。总结一下,加上transform-style:preserve-3d可以呈现3d视觉。掘金队的标志整体呈金字塔形,或者说是四棱锥(squarepyramid)。整个绘图由translate3d和rotate3d等基本操作组成。空心部分可以用渐变填充或遮罩。横截面需要稍微微调以确保横截面的大小和位置恰到好处。为了使整个模型更加逼真,需要添加合理的高光和阴影。鼠标跟随效果可以通过传递CSS变量来实现。当然,这种比较规则的图形可以通过CSS轻松处理。如果有一些不规则或曲面,就不容易实现,高光也无法真实模拟。建议只能通过three.js这样的专业图形处理库。