前端小白别慌!用HTML+CSS手搓一个会转的透明立方体(附避坑指

前端小白别慌!用HTML+CSS手搓一个会转的透明立方体(附避坑指
前端小白别慌!用HTML+CSS手搓一个会转的透明立方体(附避坑指南)
这玩意儿真不是Three.js干的?
说实话,第一次在公司技术分享会上看到同事展示这个效果的时候,我TM直接愣在原地了。当时我心里只有一个念头:这货绝对偷偷引了Three.js,说不定还加了什么WebGL的妖术。
结果人家把F12一开,HTML文件里干干净净,连个script标签都没有,纯粹的HTML+CSS,我当时就感觉CPU烧了。这不科学啊?一个方块在转,还是透明的,里面好像还有光晕,这种赛博朋克风的东西,不应该是那些写shader的大佬才能整出来的活儿吗?
后来我自己折腾了三天,总算是搞明白了——CSS 3D变换这玩意儿,纯属是被我们给低估了。它就像是厨房里那个你从来没用过的烤箱,其实它能做的事儿多到离谱,只是你一直拿它当储物柜使。
所以今天咱们就来整点实在的,不装任何库,不写一行JS,就靠HTML和CSS,手搓一个能自动旋转、带透明效果、还有那么点高级感的立方体。放心,我当年几何考38分的人都能学会,你肯定没问题。咱不搞那些学术范儿的技术文档,就像室友坐你旁边教你一样,想到哪说到哪,错了咱再改。
先别急着写代码,脑子里得有个画面
动手之前咱得先唠明白一件事儿:CSS 3D这玩意儿,本质上是让你的浏览器假装自己是个相机。想象一下你拿着手机拍一个骰子,手机离骰子多远(perspective),骰子怎么转(rotate),图片里骰子各个面怎么叠在一起(transform-style),这些就是咱们要调的东西。
很多人一上来就急吼吼地写div,结果写了一半发现立方体显示成一坨翔,或者转着转着面突然消失了,开始疯狂百度,最后在某个论坛看到一句"加个preserve-3d试试",才恍然大悟。咱不走那个弯路,先把原理掰扯清楚。
**核心三件套记死了:perspective(透视距离)、transform-style(是否保持3D)、transform(具体怎么变)。**这三兄弟但凡少一个或者位置放错了,你的立方体秒变二维平面图,还是那种小学生画的抽象派。
哦对了,忘了说,咱们要做的这个立方体,边长就定200px吧。为啥是200?因为100太小看着抠搜,300太大有些笔记本屏幕装不下,200这个数就像你点奶茶选五分糖一样,刚刚好的中庸之道。
HTML骨架——其实就是叠叠乐嘛
好,现在咱们开始搭积木。立方体嘛,六个面,小学二年级就学过了。但是在HTML里怎么表示这六个面呢?有些大聪明可能会想,用canvas画啊,用svg拼啊,大哥,咱今天说的是纯HTML+CSS,别跑题。
最朴实的办法:一个父容器当"舞台",里面六个div当"演员"。但是这里有个坑,很多人直接把六个div平铺,然后就开始写CSS,结果发现z-index乱成一锅粥,后面的面跑到前面来了,前面的面又穿模了。
**正确的姿势是:所有面都用绝对定位,让它们先在空间里重合在一起,然后再用CSS把它们推到该去的位置。**就像叠罗汉,先让六个人站一个坑里,然后再说谁往前站、谁往后站。
来看看这个结构,我加了一堆class,名字起得很随意,别笑:
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>CSS 3D立方体-纯手搓版</title><style>/* 先重置一下,省得浏览器搞事情 */*{margin: 0;padding: 0;box-sizing: border-box;}body{/* 深色背景看着比较有科技感,你懂的 */background:linear-gradient(135deg, #1e1e2e 0%, #2d2d44 100%);height: 100vh;display: flex;justify-content: center;align-items: center;/* 字体随便选一个,看着顺眼就行 */font-family:'Segoe UI','PingFang SC', sans-serif;overflow: hidden;/* 防止转动的时候出现滚动条 */}</style></head><body><!-- 这是舞台,也就是所谓的3D容器 --><divclass="scene"><!-- 这是立方体本身,负责整体旋转 --><divclass="cube"><!-- 六个面,名字起得直白点,省得自己忘了 --><divclass="face front">前</div><divclass="face back">后</div><divclass="face right">右</div><divclass="face left">左</div><divclass="face top">上</div><divclass="face bottom">下</div></div></div></body></html>看到没,就是这么简单粗暴。那个"前"啊"后"啊的文字是我故意加的,方便调试的时候看清楚哪个面是哪一面。等效果调好了你可以删掉,或者改成更酷炫的内容。
等等,有人可能会问,为啥要套两层div?一个scene一个cube?好问题!**scene负责3D透视(perspective),cube负责整体旋转和保持3D上下文。**这俩要是合一块,后面旋转的时候会出各种玄学bug,信我,我试过了,凌晨三点debug的惨痛经历。
CSS 3D这俩爹你必须认:transform-style和perspective
好,现在到了最容易翻车的地方。我敢打赌,90%的人在第一次写3D立方体的时候,都会在这里栽跟头,然后对着屏幕怀疑人生:“为啥我的方块看起来还是扁的?”
来,咱们先把基础的样式写上,然后重点剖析这俩属性:
/* 这是舞台,也就是3D空间的"相机" */.scene{width: 200px;height: 200px;/* 核心属性1:perspective,模拟相机离物体的距离 */perspective: 800px;/* 加个透视原点,让旋转看起来更自然,默认是中心,一般不用改 */perspective-origin: center center;}/* 这是立方体容器,六个面的爹 */.cube{width: 100%;height: 100%;position: relative;/* 核心属性2:transform-style,必须设置成preserve-3d! */transform-style: preserve-3d;/* 先把立方体转个角度,方便观察,后面再加动画 */transform:rotateX(-30deg)rotateY(45deg);}看好了,transform-style: preserve-3d这行代码,必须加在cube上,而且必须是cube,不是scene,也不是face。它的意思是:子元素(就是那六个面)在3D空间中变换时,保持它们自己的3D位置关系。如果不加这个,浏览器会偷懒,把所有子元素拍扁成二维的,然后叠在一起,你就看到一坨面面相觑的div,根本不是一个立方体。
然后是perspective: 800px。这个值怎么选?我试过的范围从200px到2000px都有。小于500的话,透视效果太强,有点像鱼眼镜头,立方体变形严重;大于1200的话,又太平了,看着像正交投影,立体感不足。800-1000这个区间比较保险,像手机拍出来的感觉。
哎,说到这儿我突然想起来,之前有个实习生把这俩属性写反了,perspective写给了cube,transform-style写给了scene,结果转出来效果像是被压路机碾过的立方体,笑惨了。记住啊,**perspective是给观察者的(scene),transform-style是给被观察物体的(cube)。**别搞混了,搞混了你今晚别想睡。
六个面的定位玄学——数学渣的噩梦
OK,现在到了整个项目里最考验空间想象力的环节。咱们得把这六个面,通过旋转和平移,摆到正确的位置上去。
先回顾一下初中几何知识:一个立方体,前面朝向你,后面是反的,左面是左,右面是右,上面是上,下面是下。听起来像废话是吧?但是当你开始写CSS的时候,你会发现自己的空间感可能还不如你家猫。
每个面都是200x200的正方形,先给它们个基础样式:
.face{position: absolute;width: 200px;height: 200px;/* 边框先加上,方便调试的时候看清楚边界 */border: 2px solid rgba(255, 255, 255, 0.5);/* 文字居中显示 */display: flex;justify-content: center;align-items: center;color:rgba(255, 255, 255, 0.9);font-size: 24px;font-weight: bold;/* 透明效果先用rgba背景色试水,后面再优化 */background:rgba(100, 200, 255, 0.3);/* 文字别被选中,影响观感 */user-select: none;}现在重点来了,怎么摆这六个货。核心思路是:所有面先重合在一起(绝对定位默认就是重合的),然后通过translateZ把它们推到距离中心正确的位置,再通过rotate调整朝向。
为什么要translateZ?想象一下,你站在镜子前,镜子离你10厘米,你在CSS里就让那个面translateZ(100px)。如果镜面要朝左,你就先rotateY(-90deg),然后再translateZ(100px)。注意顺序很重要!transform的执行顺序是从右往左的,或者说,后面的变换会基于前面的结果。
看代码,边长200px,所以每个面距离中心的距离应该是100px:
/* 前面:直接往前推100px,不需要旋转 */.front{transform:translateZ(100px);background:rgba(255, 100, 100, 0.3);/* 红色系,方便区分 */}/* 后面:先转180度(让它面朝后),再往后推100px */.back{transform:rotateY(180deg)translateZ(100px);background:rgba(100, 255, 100, 0.3);/* 绿色系 */}/* 右面:先顺时针转90度(朝向右边),再往右推 */.right{transform:rotateY(90deg)translateZ(100px);background:rgba(100, 100, 255, 0.3);/* 蓝色系 */}/* 左面:逆时针转90度 */.left{transform:rotateY(-90deg)translateZ(100px);background:rgba(255, 255, 100, 0.3);/* 黄色系 */}/* 上面:绕X轴转90度(抬头),往上推 */.top{transform:rotateX(90deg)translateZ(100px);background:rgba(255, 100, 255, 0.3);/* 紫色系 */}/* 下面:绕X轴顺时针转90度(低头),往下推 */.bottom{transform:rotateX(-90deg)translateZ(100px);background:rgba(100, 255, 255, 0.3);/* 青色系 */}让我解释一下这里面的坑。首先,**为什么rotateY(90deg)后面不是translateX而是translateZ?**因为rotateY之后,这个面的坐标系也跟着转了。原本面朝前的面(Z轴朝前),右转90度后,它的Z轴就指向右边了。这时候你translateZ,实际上是沿着新的Z轴(也就是全局的X轴正方向)移动。这就是CSS 3D变换最容易绕晕人的地方——每个元素都有自己的局部坐标系,变换是累加的。
我当时写这块的时候,对着草稿纸画了起码二十个坐标系,差点没把自己画emo了。如果你现在觉得晕,正常,太正常了。建议你把每个面的transform单独注释掉,一个一个加回去看效果,立马就懂了。
还有,**如果你发现立方体的某个面死活对不上缝,检查一下是不是translateZ的值错写成200px了。**必须是一半的边长,100px。要是写错了,你会发现六个面要么离中心太远散成一朵花,要么挤在一起像个骰子被踩扁了。
透明效果怎么做才不廉价——别让UI设计师笑话你
好,现在咱们有一个能看的立方体了,但是看起来吧…怎么说呢,有点像那种幼儿园手工课的作品,六个彩色的纸片粘在一起。咱们要的是"科技感"、“透明感”、“玻璃质感”,对不对?
很多人第一反应是:opacity: 0.5!打住!千万别!opacity这属性就像抗生素,虽然确实能让东西变透明,但是它太粗暴了。不仅背景变透明,边框变透明,连里面的文字也变透明,整个面看起来像被水洗过一样发白,边缘还发虚,一点质感都没有。
**正确的做法是用rgba颜色值设置背景,配合backdrop-filter模糊,再加内发光。**这套组合拳下来,UI设计师都得过来问你要源码。
来,咱们把前面的样式升级一下:
.face{position: absolute;width: 200px;height: 200px;/* 边框还是用半透明白色,但用rgba控制更精细 */border: 2px solid rgba(255, 255, 255, 0.8);border-radius: 8px;/* 微圆角,看着柔和一点 */display: flex;justify-content: center;align-items: center;color: #fff;font-size: 24px;font-weight: bold;text-shadow: 0 0 10px rgba(255,255,255,0.8);/* 文字发光 */user-select: none;/* 核心:用rgba背景,而不是opacity */background:rgba(255, 255, 255, 0.05);/* 核心:毛玻璃效果,性能开销有点大,但好看是真的 */backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);/* Safari兼容 *//* 内发光,营造玻璃质感 */box-shadow: inset 0 0 20px rgba(255, 255, 255, 0.2), 0 0 15px rgba(255, 255, 255, 0.1);/* 过渡动画,后面做交互用得上 */transition: all 0.3s ease;}看到没,这套组合拳的关键是:背景用rgba(255,255,255,0.05),透明度只有5%,几乎是完全透明的,但是因为有backdrop-filter: blur(8px),背后的内容会被模糊,产生那种磨砂玻璃的效果。
box-shadow也好玩,有两个值:第一个是inset内阴影,制造边缘发光的感觉;第二个是普通外阴影,让面有点浮起来的立体感。
**但是注意啊,backdrop-filter是个性能大户,尤其是移动端,开多了必卡。**如果你的目标用户都是用的五年前的安卓机,建议慎重,或者只在桌面端启用。当然,咱们今天是为了好看,先不管那么多,反正产品经理还没提性能需求呢(手动狗头)。
还有个小细节,文字我加了text-shadow: 0 0 10px rgba(255,255,255,0.8),就是让文字也有发光效果,这样看起来的确有点赛博朋克那味儿了。你要是觉得太中二,可以去掉,或者改成其他颜色。
让它自己转起来——animation别写成PPT
静态的立方体看着还行,但咱们要做的是"会转的透明立方体",不动起来怎么行?用JavaScript控制transform?可以,但没必要。CSS的@keyframes动画足够搞定这事儿,而且性能比JS好。
最简单的想法:写个动画,从rotateY(0deg)转到rotateY(360deg),搞定收工。等等,如果你真这么写了,运行起来会发现——怎么有点卡?像PPT翻页一样,一点也不丝滑?
问题出在两个地方:transform-origin(旋转中心)和timing-function(时间曲线)。
默认情况下,元素是绕着它自己的中心旋转的。但咱们的立方体,中心其实在scene的中间,如果每个面各自绕着自己的中心转,那画面太美我不敢看。所以咱们得让cube(六个面的爹)绕着整个立方体的中心转。
来,给cube加上动画:
.cube{width: 100%;height: 100%;position: relative;transform-style: preserve-3d;/* 关键在这:transform-origin要设成立方体的中心 *//* 前两个值是XY平面的中心,第三个值是Z轴的中心,也就是-100px(因为前面translateZ是100px)*/transform-origin: center center -100px;/* 初始状态,稍微倾斜一下,不然正对着看只能看到一个面 */transform:rotateX(-20deg)rotateY(0deg);/* 绑定动画 */animation: rotateCube 8s infinite linear;}@keyframes rotateCube{0%{transform:rotateX(-20deg)rotateY(0deg);}100%{transform:rotateX(-20deg)rotateY(360deg);}}这里我解释一下transform-origin: center center -100px。前两个center好理解,就是水平垂直居中。第三个值是Z轴的偏移量,为什么是-100px?因为咱们的立方体中心在translateZ(0)的位置(六个面分别向外推了100px,中心就在0处),但是transform-origin的第三个值默认值是0,如果不管它,立方体会绕着它自己的前面那条边旋转,看起来会很怪异。设为-100px,就是让旋转轴穿过立方体的几何中心。
其实这里我也有点含糊,这个-100px到底怎么算出来的。 我试出来的,你把六个面都推出去100px,几何中心就在原点(0,0,0)了,但是好像transform-origin的Z轴0点是参照cube本身的… 算了算了,别纠结数学原理了,就记住:**如果立方体边长200px,translateZ都是100px,那transform-origin的Z轴就写-100px。**如果不是,你就肉眼调试,看着对了就行,反正前端嘛,能跑就行(逃)。
然后是timing-function。上面代码里我写的是linear,匀速旋转,其实还可以。但如果你想更骚一点,让立方体转的时候有点弹性,像是在太空里漂浮的感觉,可以改成:
.cube{/* ... 其他样式不变 ... */animation: rotateCube 8s infinite cubic-bezier(0.68, -0.55, 0.27, 1.55);}这个cubic-bezier(0.68, -0.55, 0.27, 1.55)是个带弹性的曲线,转的时候会有点加速然后减速的感觉,不那么死板。当然,如果你喜欢机械感的匀速旋转,linear也挺好听的,各有所爱嘛。
你还可以加得更复杂一点,让X轴和Y轴同时旋转,制造出那种乱转的混沌效果:
@keyframes rotateCube{0%{transform:rotateX(0deg)rotateY(0deg)rotateZ(0deg);}33%{transform:rotateX(180deg)rotateY(120deg)rotateZ(60deg);}66%{transform:rotateX(90deg)rotateY(240deg)rotateZ(180deg);}100%{transform:rotateX(0deg)rotateY(360deg)rotateZ(360deg);}}这种多轴旋转看着很晕,但是也很酷,像是个失控的卫星。你自己把控,别让用户看晕了投诉就行。
移动端转不动?可能是你没开硬件加速
搞定了桌面端,自信满满地掏出手机一看——卧槽,怎么卡成狗?掉帧掉得比我的头发还快。这时候你就需要请出CSS硬件加速三件套了。
现代浏览器(尤其是移动端)默认是用CPU渲染动画的,一旦遇到3D变换加上透明模糊这种重活儿,CPU就罢工了。咱们得骗浏览器用GPU来渲染。
秘诀就是will-change属性和translateZ(0) hack。
给cube加上:
.cube{width: 100%;height: 100%;position: relative;transform-style: preserve-3d;transform-origin: center center -100px;animation: rotateCube 8s infinite linear;/* 硬件加速提示 */will-change: transform;/* 或者用3D变换hack强制开启GPU *//* transform: translateZ(0) rotateX(-20deg); 注意这样写会和动画冲突,慎用 */}will-change: transform就像是你提前告诉浏览器:"哥们儿,这个元素要频繁变换啊,你给我提前准备准备。"浏览器就会把它丢给GPU处理,丝滑程度立刻提升50%以上。
但是注意,**will-change别滥用。**这玩意儿占GPU内存的,如果你一个页面上有十几个立方体,都加will-change,手机当场发烫,电量肉眼可见地掉,比玩原神还耗电。只在需要动画的元素上加,而且动画结束后最好去掉。
还有个更狠的招,给container加:
.scene{width: 200px;height: 200px;perspective: 800px;/* 强制硬件加速 */transform:translateZ(0);backface-visibility: hidden;/* 这个后面会讲 */}transform: translateZ(0)这个hack是老前端都知道的,理论上移动0像素等于没动,但是浏览器看到3D变换关键字,就会强制开启GPU加速。有点像是跟浏览器说:“我这是3D的哦,你得上点心”,浏览器:“好嘞GPU走起”。
不过说实话,现在的手机浏览器越来越智能了,有时候你不加这些也跑得挺顺。但如果你的用户还在用iPhone 6s或者远古安卓机,这些优化就是救命稻草。
那些年我们一起翻的车——debug回忆录
写到这里,我突然想起那些凌晨三点还在调这个立方体的痛苦回忆。为了让你们少走弯路,我把最常见的几个坑列出来,都是血泪史啊。
坑1:立方体显示成一坨,或者只看到一个面
检查点:
- scene有没有设置宽高?没高度的话3D空间直接 collapse。必须明确写width和height。
- cube的transform-style是不是写成了flat?必须是preserve-3d。
- perspective是不是忘加了,或者加错元素了?
/* 错误示范 */.cube{transform-style: flat;/* 错了!这是默认值,会拍扁 */}/* 正确 */.cube{transform-style: preserve-3d;/* 保持3D! */}坑2:背面的面看不见,或者直接消失了
这是backface-visibility属性在搞鬼。默认值是visible,但有时候浏览器或者某些CSS框架会重置成hidden。如果你的立方体转着转着,后面的面突然透明了,能看到背后的背景,那就是这个问题。
解决办法:
.face{/* 确保背面可见 */backface-visibility: visible;/* 或者如果你想做那种"单面可见"的效果,就设成hidden *//* backface-visibility: hidden; */}注意,如果你要做那种"盒子内部是空的,只能看到外壳"的效果,反而应该把backface-visibility设成hidden。但咱们今天做的是透明立方体,要看通透感的,所以必须是visible。
坑3:z-index在3D世界里基本是个废物
在2D布局里,z-index控制谁在上面。但在3D变换里,元素的层级是由它们在3D空间中的Z坐标决定的,也就是translateZ的值。你就算给一个面写z-index: 9999,如果它的translateZ是-100px,另一个面translateZ是100px,后者还是会盖在前者上面。
所以别费劲调z-index了,盯着你的translateZ值看,那才是真正的"Z轴层级"。
坑4:鼠标事件穿透问题
透明立方体转起来的时候,你想点下面的某个面,结果发现点不到,事件被上层的面截获了。这是因为3D空间里的鼠标事件处理跟视觉顺序不一定一致。
如果你想让立方体只是个展示,不影响点击页面其他内容:
.scene{pointer-events: none;}如果你想让立方体能交互,但内部的结构不影响事件:
.cube{pointer-events: none;}.face{pointer-events: auto;/* 只有面能接收事件 */}坑5:模糊效果导致文字看不清
backdrop-filter: blur()开太高的话,如果后面有复杂背景,前面的文字确实会看起来很糊。这时候要么降低blur值,要么给文字加个半透明的背景色垫底,别直接让文字浮在模糊层上。
整点花活儿——让你的立方体更带感
基础功能搞定了,现在咱们来加点料,让这玩意儿看起来更贵(毕竟贵的就是好的)。
骚操作1:鼠标悬停交互
让立方体平时自己转,鼠标放上去的时候停下来,或者转反方向?
.cube{animation: rotateCube 8s infinite linear;transition: animation-play-state 0.3s;}/* 鼠标悬停暂停 */.cube:hover{animation-play-state: paused;}/* 或者这样,鼠标悬停加速 */.cube:hover{animation-duration: 2s;/* 转得飞起 */}/* 反转也可以,虽然有点晕 */.cube:hover{animation-direction: reverse;}骚操作2:每个面贴不同的渐变背景,假装材质系统
纯色太low?上渐变!
.front{transform:translateZ(100px);background:linear-gradient(135deg,rgba(255,0,0,0.4) 0%,rgba(255,100,100,0.2) 100%);border-color:rgba(255,100,100,0.6);}.back{transform:rotateY(180deg)translateZ(100px);background:linear-gradient(135deg,rgba(0,255,0,0.4) 0%,rgba(100,255,100,0.2) 100%);border-color:rgba(100,255,100,0.6);}/* 其他面同理... */这样每个面都有自己的"主题色",转起来像 disco 球一样,虽然有点土嗨,但是客户喜欢啊。
骚操作3:内部光晕,赛博朋克风
在cube里面再加个伪元素,做个中心发光体:
.cube::before{content:'';position: absolute;width: 50px;height: 50px;background:radial-gradient(circle,rgba(255,255,255,0.8) 0%, transparent 70%);top: 50%;left: 50%;transform:translate(-50%, -50%)translateZ(0);box-shadow: 0 0 50px 20px rgba(100,200,255,0.5);pointer-events: none;animation: pulse 2s infinite;}@keyframes pulse{0%, 100%{opacity: 0.8;transform:translate(-50%, -50%)translateZ(0)scale(1);}50%{opacity: 0.4;transform:translate(-50%, -50%)translateZ(0)scale(1.2);}}这样立方体中心有个会呼吸的光球,透过透明面看进去,是不是有点科幻片里能量核心的感觉了?UI小姐姐看了直呼内行。
骚操作4:鼠标跟随视角
虽然咱们说不写JS,但如果你想加点简单的交互,用一点点JS让立方体跟着鼠标方向转,体验立马升级:
<script>// 就加这么一点,不算犯规吧? document.addEventListener('mousemove',(e)=>{const cube = document.querySelector('.cube');const x =(window.innerWidth /2- e.pageX)/20;const y =(window.innerHeight /2- e.pageY)/20;// 覆盖CSS的旋转,让鼠标控制 cube.style.transform =`rotateY(${x}deg) rotateX(${y}deg)`;// 注意这样会把自动动画覆盖掉,鱼和熊掌不可兼得});</script>这段代码会让立方体跟着鼠标动,像是在用鼠标"抓"着它看不同角度。但是它会覆盖掉CSS动画,所以你要么二选一,要么写复杂点把两者结合,那个就超出今天的话题范围了。
最终的完整代码——拿去装逼不谢
行了,啰嗦了这么多,给你们一份可以直接复制粘贴跑起来的完整代码,注释写得满满的,拿去改改色值就能用:
<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><metaname="viewport"content="width=device-width, initial-scale=1.0"><title>纯CSS 3D透明立方体 - 极致版</title><style>*{margin: 0;padding: 0;box-sizing: border-box;}body{background:linear-gradient(135deg, #0f0c29 0%, #302b63 50%, #24243e 100%);height: 100vh;display: flex;flex-direction: column;justify-content: center;align-items: center;font-family:'Segoe UI', system-ui, -apple-system, sans-serif;overflow: hidden;color: #fff;}h1{margin-bottom: 50px;font-size: 2rem;text-shadow: 0 0 20px rgba(255,255,255,0.5);font-weight: 300;letter-spacing: 2px;}/* 3D舞台 - 所有透视效果的基础 */.scene{width: 200px;height: 200px;perspective: 1000px;/* 透视距离,调大调小看喜好 */perspective-origin: center center;/* 硬件加速,移动端必备 */transform:translateZ(0);}/* 立方体容器 - 六个面的爹 */.cube{width: 100%;height: 100%;position: relative;transform-style: preserve-3d;/* 核心!保持3D上下文 */transform-origin: center center -100px;/* 旋转中心修正 *//* 初始倾斜角度 + 自动旋转动画 */transform:rotateX(-30deg)rotateY(0deg);animation: rotateCube 12s infinite linear;will-change: transform;/* 性能优化 */}/* 鼠标悬停效果:暂停并放大 */.scene:hover .cube{animation-play-state: paused;transition: transform 0.5s ease;}/* 立方体六个面的基础样式 */.face{position: absolute;width: 200px;height: 200px;border: 2px solid rgba(255, 255, 255, 0.6);border-radius: 12px;display: flex;flex-direction: column;justify-content: center;align-items: center;color:rgba(255, 255, 255, 0.95);font-size: 20px;font-weight: 600;text-shadow: 0 0 10px rgba(255,255,255,0.8);/* 玻璃拟态效果 */background:rgba(255, 255, 255, 0.08);backdrop-filter:blur(12px);-webkit-backdrop-filter:blur(12px);/* 边缘发光 + 外发光 */box-shadow: inset 0 0 30px rgba(255, 255, 255, 0.2), 0 0 20px rgba(255, 255, 255, 0.15);/* 确保背面可见 */backface-visibility: visible;/* 交互反馈 */transition: all 0.3s ease;cursor: pointer;}/* 各个面的独立定位和颜色主题 */.face-front{transform:translateZ(100px);background:linear-gradient(135deg,rgba(255,100,100,0.15) 0%,rgba(255,100,100,0.05) 100%);border-color:rgba(255,100,100,0.5);}.face-back{transform:rotateY(180deg)translateZ(100px);background:linear-gradient(135deg,rgba(100,255,100,0.15) 0%,rgba(100,255,100,0.05) 100%);border-color:rgba(100,255,100,0.5);}.face-right{transform:rotateY(90deg)translateZ(100px);background:linear-gradient(135deg,rgba(100,100,255,0.15) 0%,rgba(100,100,255,0.05) 100%);border-color:rgba(100,100,255,0.5);}.face-left{transform:rotateY(-90deg)translateZ(100px);background:linear-gradient(135deg,rgba(255,255,100,0.15) 0%,rgba(255,255,100,0.05) 100%);border-color:rgba(255,255,100,0.5);}.face-top{transform:rotateX(90deg)translateZ(100px);background:linear-gradient(135deg,rgba(255,100,255,0.15) 0%,rgba(255,100,255,0.05) 100%);border-color:rgba(255,100,255,0.5);}.face-bottom{transform:rotateX(-90deg)translateZ(100px);background:linear-gradient(135deg,rgba(100,255,255,0.15) 0%,rgba(100,255,255,0.05) 100%);border-color:rgba(100,255,255,0.5);}/* 面的内容样式 - 可以放个icon或者文字 */.face-content{font-size: 14px;margin-top: 10px;opacity: 0.8;}/* 核心旋转动画 - 围绕Y轴转一圈 */@keyframes rotateCube{0%{transform:rotateX(-30deg)rotateY(0deg);}100%{transform:rotateX(-30deg)rotateY(360deg);}}/* 面的悬停效果 - 高亮当前面 */.face:hover{background:rgba(255, 255, 255, 0.2);box-shadow: inset 0 0 40px rgba(255, 255, 255, 0.4), 0 0 30px rgba(255, 255, 255, 0.3);border-color:rgba(255, 255, 255, 0.9);}/* 装饰性文字说明 */.tips{margin-top: 60px;font-size: 14px;color:rgba(255,255,255,0.6);text-align: center;line-height: 1.6;max-width: 400px;}.tips span{color:rgba(100, 200, 255, 0.9);font-weight: 600;}/* 移动端适配 - 缩小一点 */@media(max-width: 600px){.scene{width: 150px;height: 150px;perspective: 800px;}.face{width: 150px;height: 150px;font-size: 16px;}/* 重新计算translateZ,边长150的一半是75 */.face-front{transform:translateZ(75px);}.face-back{transform:rotateY(180deg)translateZ(75px);}.face-right{transform:rotateY(90deg)translateZ(75px);}.face-left{transform:rotateY(-90deg)translateZ(75px);}.face-top{transform:rotateX(90deg)translateZ(75px);}.face-bottom{transform:rotateX(-90deg)translateZ(75px);}.cube{transform-origin: center center -75px;}}</style></head><body><h1>CSS 3D Glass Cube</h1><divclass="scene"><divclass="cube"><divclass="face face-front"> FRONT <spanclass="face-content">前面</span></div><divclass="face face-back"> BACK <spanclass="face-content">后面</span></div><divclass="face face-right"> RIGHT <spanclass="face-content">右面</span></div><divclass="face face-left"> LEFT <spanclass="face-content">左面</span></div><divclass="face face-top"> TOP <spanclass="face-content">顶面</span></div><divclass="face face-bottom"> BOTTOM <spanclass="face-content">底面</span></div></div></div><divclass="tips"><span>纯HTML+CSS实现</span> · 无需JavaScript<br> 鼠标悬停可暂停旋转 · 支持移动端查看 </div></body></html>看到没,代码量其实不大,但是每一行都有它的道理。那个@media查询是做什么的?移动端适配啊!不然在手机上200px的立方体可能太大了,缩成150px看着舒服点。注意translateZ和transform-origin的Z值也要跟着变,不然对不上缝。
最后的吐槽——前端的浪漫往往死于需求变更
代码写完了,效果也有了,这时候你可能会想:老子真是个天才,这效果太酷炫了,我要把它放在公司官网首页!
等等,哥,听我一句劝。在做这事儿之前,务必先拿着demo去找产品经理看一眼。 别问我为什么强调这个,问就是血泪教训。
我之前就搞过一个类似的3D展示效果,熬了三个晚上调细节,自以为完美无缺。结果给产品一看,人家皱着眉头说:“这个立方体…能不能做成圆角立方体?就像苹果那个垃圾桶Mac Pro一样的那种?”
我当时差点当场ICU。圆角立方体?大哥,CSS 3D变出来的立方体,边框你看着是直的,其实是伪3D,真要做圆角立方体那得用WebGL,Three.js,还得上建模。我试图解释技术难度,产品满脸疑惑:“不就是改个border-radius吗?你不是写好了吗,把那个8px改成50%不就行了?”
border-radius 50%… 他说得轻描淡写,我听得心梗发作。就像你跟理发师说稍微修一下,结果他给你推了个寸头一样绝望。
所以啊,这种hack性质很强的CSS技巧,适合做技术分享、写博客装逼、或者放在个人作品集里展示前端功底。 真要上生产环境,尤其是需要长期维护的项目,你得考虑清楚:如果明天需求改成"里面再放个小一号的立方体并且反向旋转",你还能接单吗?如果设计师说"我要每个面贴不同的产品图片还要高清不模糊",你的backdrop-filter会不会卡死?
说到底,CSS 3D是个玩具属性,玩玩可以,拿来炫技可以,当成正经架构来做就危险了。但话说回来,前端这活儿,不就是每天在各种"不可能"和"试试呗"之间反复横跳吗?能用手里现有的工具整出花活,本身就是种浪漫。
好了,今天就唠到这儿。代码拿去用,遇到问题自己先调调perspective值,百分之八十的显示问题都是靠调这个解决的。记住,**前端开发的第一准则:如果看起来对了,那就是对了,别深究为什么。**咱们山顶见。
欢迎来到我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
推荐:DTcode7的博客首页。
一个做过前端开发的产品经理,经历过睿智产品的折磨导致脱发之后,励志要翻身农奴把歌唱,一边打入敌人内部一边持续提升自己,为我们广大开发同胞谋福祉,坚决抵制睿智产品折磨我们码农兄弟!
| 专栏系列(点击解锁) | 学习路线(点击解锁) | 知识定位 |
|---|---|---|
| 《微信小程序相关博客》 | 持续更新中~ | 结合微信官方原生框架、uniapp等小程序框架,记录请求、封装、tabbar、UI组件的学习记录和使用技巧等 |
| 《AIGC相关博客》 | 持续更新中~ | AIGC、AI生产力工具的介绍,例如stable diffusion这种的AI绘画工具安装、使用、技巧等总结 |
| 《HTML网站开发相关》 | 《前端基础入门三大核心之html相关博客》 | 前端基础入门三大核心之html板块的内容,入坑前端或者辅助学习的必看知识 |
| 《前端基础入门三大核心之JS相关博客》 | 前端JS是JavaScript语言在网页开发中的应用,负责实现交互效果和动态内容。它与HTML和CSS并称前端三剑客,共同构建用户界面。 通过操作DOM元素、响应事件、发起网络请求等,JS使页面能够响应用户行为,实现数据动态展示和页面流畅跳转,是现代Web开发的核心 | |
| 《前端基础入门三大核心之CSS相关博客》 | 介绍前端开发中遇到的CSS疑问和各种奇妙的CSS语法,同时收集精美的CSS效果代码,用来丰富你的web网页 | |
| 《canvas绘图相关博客》 | Canvas是HTML5中用于绘制图形的元素,通过JavaScript及其提供的绘图API,开发者可以在网页上绘制出各种复杂的图形、动画和图像效果。Canvas提供了高度的灵活性和控制力,使得前端绘图技术更加丰富和多样化 | |
| 《Vue实战相关博客》 | 持续更新中~ | 详细总结了常用UI库elementUI的使用技巧以及Vue的学习之旅 |
| 《python相关博客》 | 持续更新中~ | Python,简洁易学的编程语言,强大到足以应对各种应用场景,是编程新手的理想选择,也是专业人士的得力工具 |
| 《sql数据库相关博客》 | 持续更新中~ | SQL数据库:高效管理数据的利器,学会SQL,轻松驾驭结构化数据,解锁数据分析与挖掘的无限可能 |
| 《算法系列相关博客》 | 持续更新中~ | 算法与数据结构学习总结,通过JS来编写处理复杂有趣的算法问题,提升你的技术思维 |
| 《IT信息技术相关博客》 | 持续更新中~ | 作为信息化人员所需要掌握的底层技术,涉及软件开发、网络建设、系统维护等领域的知识 |
| 《信息化人员基础技能知识相关博客》 | 无论你是开发、产品、实施、经理,只要是从事信息化相关行业的人员,都应该掌握这些信息化的基础知识,可以不精通但是一定要了解,避免日常工作中贻笑大方 | |
| 《信息化技能面试宝典相关博客》 | 涉及信息化相关工作基础知识和面试技巧,提升自我能力与面试通过率,扩展知识面 | |
| 《前端开发习惯与小技巧相关博客》 | 持续更新中~ | 罗列常用的开发工具使用技巧,如 Vscode快捷键操作、Git、CMD、游览器控制台等 |
| 《photoshop相关博客》 | 持续更新中~ | 基础的PS学习记录,含括PPI与DPI、物理像素dp、逻辑像素dip、矢量图和位图以及帧动画等的学习总结 |
| 日常开发&办公&生产【实用工具】分享相关博客》 | 持续更新中~ | 分享介绍各种开发中、工作中、个人生产以及学习上的工具,丰富阅历,给大家提供处理事情的更多角度,学习了解更多的便利工具,如Fiddler抓包、办公快捷键、虚拟机VMware等工具 |
吾辈才疏学浅,摹写之作,恐有瑕疵。望诸君海涵赐教。望轻喷,嘤嘤嘤
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。愿斯文对汝有所裨益,纵其简陋未及渊博,亦足以略尽绵薄之力。倘若尚存阙漏,敬请不吝斧正,俾便精进!