一、为什么要关心 CSS 3D?
提到网页 3D,很多人第一反应是 WebGL、Three.js、canvas。这些技术确实强大,但它们的学习曲线陡峭,上手成本高。其实,CSS 本身就能做 3D------而且比你想象的更简单、更实用。
CSS 3D 的价值远不止"做个旋转的立方体看看":
- GPU 加速 :一旦你使用了
transform属性,浏览器会自动将元素提升到 GPU 合成层。这意味着即便你的页面是纯 2D 的,手动"3D 化"也能带来肉眼可见的性能提升------动画更流畅、滚动更丝滑。 - 零依赖:不需要引入任何 JS 库,纯 CSS + HTML 就能实现惊艳的 3D 效果。
- 渐进增强:不支持 3D 的浏览器会优雅降级为平面展示,不影响核心内容。
本文的项目代码就很好地体现了这一点------common.css 中每一行 CSS 都在为 GPU 渲染铺路。
二、地基:viewport 与弹性布局
在看 3D 代码之前,先来看基础布局的选择。common.css 的前几行就做了非常关键的决策:
css
html, body {
height: 100vh;
display: flex;
justify-content: center;
align-items: center;
}
2.1 100vh ------ CSS3 的新单位
vh 是 CSS3 引入的视口单位,1vh 等于视口高度的 1%。配合 100vh,页面容器就能精确撑满整个可视区域,无论设备是手机、平板还是桌面显示器。
它的兄弟单位还有:
单位
含义
vh
Viewport Height,视口高度的 1%
vw
Viewport Width,视口宽度的 1%
vmin
vh 和 vw 中较小的那个
vmax
vh 和 vw 中较大的那个
在移动端适配场景下,vh/vw 可以替代传统的百分比 + rem 方案,让元素尺寸真正"随屏应变"。
2.2 Flexbox ------ 移动端最常用的布局
项目注释中写道:"弹性布局,移动端视窗大小多变最常用布局"。这是经验之谈------在屏幕尺寸千变万化的今天,flex 的弹性伸缩能力让它成为布局的首选。
justify-content: center 控制主轴居中,align-items: center 控制交叉轴居中,两行代码就实现了经典的水平垂直居中------这曾经是前端面试的"必考题",用 flex 解决起来却如此简单。
三、理解 CSS 盒子模型的前置知识
在动手写 3D 之前,项目还用 2.html 和 3.html 介绍了两个关键概念:
3.1 行内 vs 块级
HTML 元素分为两大类:
- 块级(block) :
div、ul、p等,独占一行,可以设置宽高。 - 行内(inline) :
span、a等,不独占一行,但 不能设置宽高。
display 属性让我们可以手动切换这个行为:
display: block→ 变成块级display: inline→ 变成行内display: inline-block→ 行内块级:不挤走兄弟,又能设置宽高
2.html 就展示了两个 inline-block 的 div 并排排列的场景。但要注意 inline-block 的"天坑":HTML 源码中的换行符会被渲染为一个空格,导致元素之间出现意料之外的间隙。
3.2 格式化上下文
当 display 的值是 flex、grid、inline-block 时,我们不仅仅是改变了元素的显示方式,更是开启了一个新的格式化上下文。在这个上下文中,子元素的布局规则完全改变------比如 flex 容器中,子元素默认沿主轴排列,由父元素统一管理。
3.html 的 display: flex + flex: 1 组合,让四个子元素等分父容器宽度,这就是弹性布局格式化上下文的威力。
四、CSS 3D 的核心四件套
现在进入正题。要让一个元素进入 3D 空间,你需要掌握四个关键属性:
4.1 perspective ------ 3D 的"眼睛"
css
.box-wrap {
perspective: 600px;
}
perspective 定义了观察者与屏幕的距离。值越小,3D 效果越夸张(就像你把脸贴近屏幕);值越大,3D 效果越平缓。这个属性必须设置在父容器上,它影响的是子元素的 3D 表现。
可以这样理解:perspective 就是你的眼睛距离舞台的距离。距离越近,近大远小的透视效果越明显。
4.2 transform-style: preserve-3d ------ 保护 3D 空间
css
.box {
transform-style: preserve-3d;
}
默认情况下,一个元素在做了 3D 变换后,它的子元素仍然被"压扁"在父元素的平面上。preserve-3d 的作用是告诉浏览器:请保留这个元素内部的三维空间,让子元素可以在 Z 轴上自由排布。
没有这行代码,你的六个面会全部叠在同一平面上,立方体就变成了一个奇怪的六边形------这可能是调试 CSS 3D 时最常遇到的坑。
4.3 transform 的 3D 函数
这是真正让元素在三维空间中移动和旋转的武器:
函数
作用
translateZ(d)
沿 Z 轴向屏幕外(正)或屏幕内(负)移动
translateX(d)
沿 X 轴左右移动
translateY(d)
沿 Y 轴上下移动
rotateX(d)
绕 X 轴旋转(前后翻)
rotateY(d)
绕 Y 轴旋转(水平转)
rotateZ(d)
绕 Z 轴旋转(平面转)
在 common.css 中,立方体的六个面各自用了不同的变换组合:
css
.front { transform: translateZ(100px); }
.back { transform: translateZ(-100px) rotateY(180deg); }
.left { transform: translateX(-100px) rotateY(-90deg); }
.right { transform: translateX(100px) rotateY(90deg); }
.top { transform: translateY(-100px) rotateX(90deg); }
.bottom { transform: translateY(100px) rotateX(90deg); }
立方体的边长是 200px,所以每个面平移 100px(半边长)就能恰好围成一个闭合的立方体。你可以想象成:把六张扑克牌从中心点各推出去 100px,每张牌朝向不同的方向------就是立方体了。
小贴士:代码注释中特意标注了"顺时针"和"逆时针"------当你设置
rotateY的正负值时,旋转方向是不同的。这在多层嵌套变换时非常重要,方向搞反了,面就会朝里而非朝外。
4.4 @keyframes ------ 让立方体动起来
css
animation: rotate 5s linear infinite;
@keyframes rotate {
100% {
transform: rotateY(0deg) rotateX(720deg) rotateZ(720deg);
}
}
animation 属性把 @keyframes 定义的动画绑定到元素上:
rotate是自定义的动画名称(可以理解成导演的名字)5s是一次动画的持续时间linear表示匀速播放infinite表示无限循环
这里的动画逻辑很简洁:5 秒内绕 X 轴和 Z 轴各转两圈(720°),实际效果是立方体以丰富的姿态不断翻转------因为三个轴同时旋转,每次回到原位时展示的角度都不同。
五、absolute + relative 的经典配合
要让六个面全部重叠在同一位置,然后各自向不同方向平移,需要用到定位的经典组合:
- 父容器 (
.box):position: relative------ 建立定位参考系,但不移动自身。 - 子元素 (
.face):position: absolute------ 脱离文档流,相对于最近的relative祖先定位。
六个面全部 absolute 定位后,它们默认堆叠在父容器的 (0, 0) 点。然后每个面通过不同的 transform 值散开到各自的 3D 位置------这就是六面体的几何构建原理。这是一种"先聚合、再分散"的设计模式,非常优雅。
六、完整架构回顾
把整个项目的架构串起来看:
yaml
┌──────────────────────────────────────┐
│ html, body │
│ height: 100vh → 撑满视口 │
│ display: flex → 弹性居中 │
│ │
│ ┌──────────────────────────────┐ │
│ │ .box-wrap │ │
│ │ width/height: 200px │ │
│ │ perspective: 600px ← 3D视角│ │
│ │ │ │
│ │ ┌──────────────────────┐ │ │
│ │ │ .box │ │ │
│ │ │ position: relative │ │ │
│ │ │ preserve-3d ← 3D空间 │ │ │
│ │ │ animation: rotate │ │ │
│ │ │ │ │ │
│ │ │ .face × 6 │ │ │
│ │ │ position: absolute │ │ │
│ │ │ transform: 各向平移 │ │ │
│ │ └──────────────────────┘ │ │
│ └──────────────────────────────┘ │
└──────────────────────────────────────┘
这是一个典型的双层包装结构 :外层 .box-wrap 负责 3D 视角(perspective),内层 .box 负责 3D 变换和动画,最内层的 .face 负责每个面的定位。职责分离得干干净净,修改透视效果不会影响动画逻辑,修改动画不会影响面的几何关系。
七、实战延伸:你还可以做什么?
掌握了这些基础,你已经可以创造出很多有趣的效果:
- 3D 卡片翻转:鼠标悬停时卡片沿 Y 轴翻转 180 度,正面是封面,背面是详情。电商产品展示页的经典交互。
- 3D 轮播图:多个面板围成一个环,每次旋转 60 度展示下一张,视觉冲击力远超普通轮播。
- 视差滚动 :利用
translateZ将不同图层的元素放在不同深度,滚动时近处的元素移动更快,营造自然深度感。 - 3D 导航菜单:菜单项像旋转木马一样排列,hover 时向前突出,交互感极强。
- GPU 加速的 2D 动画 :即使你不需要真 3D,给 2D 动画元素加上
transform: translateZ(0)也能强制开启 GPU 合成,让低端设备上的动画流畅起来。
八、浏览器兼容性与注意事项
transform-style: preserve-3d在 IE 完全不支持,Edge 12+ 开始支持,主流现代浏览器(Chrome、Firefox、Safari)均无问题。perspective的取值需要根据元素尺寸调整------一个 100px 的盒子和一个 1000px 的盒子用同样的perspective值,3D 效果差异会非常大。经验公式:perspective设为元素尺寸的 2~4 倍左右效果最自然。- 3D 变换是纯视觉的,不会影响文档流------其他元素不会因为你的立方体"伸出来一块"而自动避让。如果需要,自己手动留出空间。
- 过度使用 3D 变换可能导致 GPU 内存占用增加,移动端尤其要注意------不要在一个页面上放几十个同时旋转的立方体。
写在最后
CSS 3D 是一个被严重低估的技术方向。很多前端开发者一听到"3D"就本能地觉得这是 WebGL 的领域,而忽略了 CSS 自身强大的 3D 能力。本文的项目虽然代码量不大------主文件 common.css 只有 78 行------但已经完整展示了一个 3D 立方体的所有核心技术点:视口适配、弹性布局、定位体系、3D 变换、关键帧动画。
这些概念分开来看都不难,组合在一起就是一座通向更多复杂效果的桥梁。从今天开始,试着在你的项目中加一点 CSS 3D------哪怕只是一个翻转的按钮、一个带景深的卡片------你会发现网页设计突然多了一个维度,那个维度叫 "深度"。