前言
前端做 3D,很多人的第一反应是 Three.js、WebGL,仿佛不搬出这些重型武器就与三维无缘。但其实,CSS 本身就内建了一套 3D 引擎 ------不需要引入任何第三方库,几行样式就能在浏览器里渲染出一个完整的 3D 立方体,而且自带 GPU 加速,性能丝毫不虚。
这篇文章会从最基础的布局原理讲起,一步步过渡到 CSS 3D 的核心属性,最终带你写出一个持续旋转、六面不同色的 3D 立方体。所有代码都来自实战,放心食用!

一、先聊布局:HTML5 的三次进化
在进入 3D 世界之前,有必要把地基打好。CSS 3D 依赖的核心属性(transform、perspective)是和布局体系深度耦合的,布局不扎实,后面写 3D 只会一头雾水。
1.1 行内与块级:浏览器的默认剧本
HTML 元素天生分为两派:
| 类型 | 代表元素 | 能设宽高? | 会独占一行? |
|---|---|---|---|
| 块级 (block) | div、ul、p |
可以 | 会,把兄弟元素挤到下一行 |
| 行内 (inline) | span、a、em |
不可以 | 不会,和兄弟元素和平共处 |
浏览器给你设好了默认值,但你随时可以用 display 属性翻盘:
css
div {
display: inline; /* 块级变行内 */
}
span {
display: block; /* 行内变块级 */
}
1.2 inline-block:鱼和熊掌兼得
有时候我们需要一个元素既能设宽高,又不会把兄弟挤下去 。display: inline-block 就是为这个场景而生的。
html
<div class="box">前</div>
<div class="box">后</div>
css
.box {
background-color: rgb(192, 31, 58);
display: inline-block;
width: 49.5%;
}
两个 div 并排显示,各自占近一半宽度------既能控制尺寸,又不会换行。
但 inline-block 有一个天坑 :元素之间的空白符(回车、空格)会被渲染成可见间隙。上面代码里两个 div 之间明明没有任何 margin,却会凭空多出几像素的间距。这是因为 HTML 源码中标签之间的换行和缩进被解析成了一个空格字符。
解决办法也很粗暴:要么把两个标签写在同一行------</div><div>;要么父容器设 font-size: 0。
1.3 Flexbox:现代布局的银弹
inline-block 虽然能用,但终究是旧时代的产物。真正的布局之王是 display: flex。
css
.box {
display: flex;
}
.item {
flex: 1;
background-color: rgb(157, 30, 51);
text-align: center;
}
一旦给父容器开启 flex,它就建立了一个弹性格式化上下文(Flex Formatting Context)。自此,子元素的排列不再受块级/行内规则的约束,而是由主轴(默认水平)和交叉轴(默认垂直)来管理。
三句话记住 Flexbox 的精髓:
- 父容器管布局方向 (
flex-direction),子元素管自己占多少(flex) - 主轴对齐用
justify-content,交叉轴对齐用align-items** - Flex 是移动端的首选布局方案,因为视窗尺寸多变,弹性比例天然适配
二、水平垂直居中:从土办法到最优解
居中是一个看似简单实则暗藏玄机的话题。我们直接看最优解:
css
html, body {
height: 100%;
display: flex;
justify-content: center; /* 主轴水平居中 */
align-items: center; /* 交叉轴垂直居中 */
}
这里有两层设计:
第一层:height: 100% 。html 和 body 默认高度是由内容撑开的,不显式设 100% 的话,垂直居中无处发力。
第二层:Flex 双轴居中 。Flex 容器的默认主轴是水平方向(flex-direction: row),所以 justify-content: center 管水平居中,align-items: center 管垂直居中。如果你把主轴改成垂直方向(flex-direction: column),这两个属性的职责也会互换。
这个组合是我个人最推荐的通用居中方案------不需要知道子元素尺寸,不需要 transform: translate(-50%, -50%) 的 hack,纯天然、零副作用。
附赠:CSS3 新视口单位
css
body {
height: 100vh; /* viewport-height,视口高度 */
width: 100vw; /* viewport-width,视口宽度 */
}
vh / vw 是 CSS3 引入的单位,把视口等分成 100 份:
100vh= 视口的完整高度50vw= 视口宽度的一半
这对移动端适配尤其有用------不再需要 height: 100% 从根节点一层层往下传,直接用 100vh 一步到位。
三、定位体系:relative 与 absolute 的共生关系
CSS 3D 构建立方体时,6 个面必须叠放在同一位置再各自平移旋转。这个"叠放"操作全靠定位:
css
.box {
position: relative; /* 作为绝对定位的参照坐标系 */
}
.face {
position: absolute; /* 脱离文档流,相对于最近的定位祖先定位 */
left: 0;
top: 0;
}
关键理解:
position: relative本身不影响元素在文档流中的位置,但它建立了一个定位上下文 ,成为后代absolute元素的"锚点"。position: absolute脱离文档流,不再占据空间,相对于最近的已定位祖先(position 不为 static 的)进行定位。- 6 个面全部
left: 0; top: 0,天然叠在同一位置,之后再各自听transform的号令向不同方向平移。
四、核心:CSS 3D 属性详解
终于进入正题。CSS 的 3D 能力由三个核心属性撑起:
4.1 perspective------3D 世界的眼睛
css
.box-wrap {
width: 200px;
height: 200px;
perspective: 600px;
}
perspective 定义了观察者眼睛到屏幕的距离,也叫"视距"。
- 数值越小 → 眼睛离屏幕越近 → 3D 透视感越强(变形越夸张)
- 数值越大 → 眼睛离屏幕越远 → 3D 效果越平缓(接近正交投影)
玩 3D 游戏的同学可以把 perspective 理解为相机的 FOV(视场角),数值越小 FOV 越大,画面透视畸变越明显。
注意 :perspective 必须设在 3D 场景的父容器上,直接写在 3D 元素自身上是无效的。
4.2 transform-style: preserve-3d------保留三维空间
css
.box {
transform-style: preserve-3d;
}
这是 CSS 3D 中最容易被忽略但绝对不可或缺的属性。
默认情况下,当父元素做 3D 变换时,浏览器会把所有子元素"拍扁"成一张 2D 图片再渲染------这叫做 transform-style: flat(默认值)。
只有显式声明 preserve-3d,子元素才能真正存在于三维空间中,各自保持独立深度(Z 轴位置)。
一句话:没有 preserve-3d,你的 3D 场景永远是一张二维贴图。
4.3 transform 平移与旋转------给每个面安排位置
一个立方体有 6 个面。假设立方体边长为 100px,半边长就是 50px。每个面需要从中心位置平移 50px 再旋转:
css
/* 前面:向屏幕外(观察者方向)平移 50px */
.front {
transform: translateZ(50px);
}
/* 后面:向屏幕内平移 50px,再旋转 180° 让文字正向 */
.back {
transform: translateZ(-50px) rotateY(180deg);
}
/* 左面:向左平移 50px,绕 Y 轴逆时针旋转 90° */
.left {
transform: translateX(-50px) rotateY(-90deg);
}
/* 右面:向右平移 50px,绕 Y 轴顺时针旋转 90° */
.right {
transform: translateX(50px) rotateY(90deg);
}
/* 上面:向上平移 50px,绕 X 轴顺时针旋转 90° */
.top {
transform: translateY(-50px) rotateX(90deg);
}
/* 下面:向下平移 50px,绕 X 轴逆时针旋转 90° */
.bottom {
transform: translateY(50px) rotateX(-90deg);
}
理解这个的时候,可以想象你手里拿着一个魔方:
- 先把六个面的贴纸都揭下来放在桌上,全部正面朝上(这就是
position: absolute; left: 0; top: 0的状态) - 然后把"前面"的贴纸向自己方向推 50px
- 把"后面"的贴纸向远离自己方向推 50px,再翻转过来
- 把"左面"往左推,然后绕竖轴转 90° 立起来
- 以此类推......
重要 :transform 属性的多个值之间用空格分隔,不能用逗号 。而且书写顺序至关重要------translateZ(50px) rotateY(180deg) 和 rotateY(180deg) translateZ(50px) 的结果完全不同,因为旋转会改变元素的局部坐标系。
五、动画:让立方体转起来
静态的立方体不够过瘾。一个 @keyframes 动画让它永动旋转:
css
.box {
animation: rotate 1s linear infinite;
}
@keyframes rotate {
0% {
transform: rotateY(0deg);
}
100% {
transform: rotateY(360deg);
}
}
rotate:自定义的动画名称,随便取1s:一轮动画的持续时间linear:匀速运动(默认是ease,会先加速后减速,立方体转动会显得一顿一顿的)infinite:无限循环
踩坑提示 :如果你既给 .box 写了静态的 transform(比如 transform: rotateY(60deg)),又通过动画操作 transform,两者会互相覆盖而不是叠加。动画的 transform 会完全取代静态的 transform。解决方案是把初始状态写在 @keyframes 的 0% 里。
六、完整代码
HTML 结构
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>CSS 3D 旋转立方体</title>
<link rel="stylesheet" href="./common.css">
</head>
<body>
<div class="box-wrap">
<div class="box">
<div class="face front">前</div>
<div class="face back">后</div>
<div class="face left">左</div>
<div class="face right">右</div>
<div class="face top">上</div>
<div class="face bottom">下</div>
</div>
</div>
</body>
</html>
CSS 样式(common.css)
css
/* ===== 全局重置 ===== */
* {
margin: 0;
padding: 0;
}
/* ===== 页面容器:Flex 居中 ===== */
html, body {
height: 100%;
display: flex;
justify-content: center;
align-items: center;
}
/* ===== 透视父容器:提供 3D 视距 ===== */
.box-wrap {
width: 200px;
height: 200px;
perspective: 600px;
}
/* ===== 立方体核心容器 ===== */
.box {
width: 100px;
height: 100px;
position: relative;
transform-style: preserve-3d;
animation: rotate 1s linear infinite;
}
/* ===== 旋转动画 ===== */
@keyframes rotate {
0% { transform: rotateY(0deg); }
100% { transform: rotateY(360deg); }
}
/* ===== 6 个面的公共样式 ===== */
.face {
width: 100px;
height: 100px;
position: absolute;
left: 0;
top: 0;
display: flex;
justify-content: center;
align-items: center;
font-size: 24px;
color: #fff;
}
/* ===== 6 个面各自定位 ===== */
.front { background: rgb(65, 28, 214); transform: translateZ(50px); }
.back { background: rgb(183, 212, 16); transform: translateZ(-50px) rotateY(180deg); }
.left { background: rgb(28, 214, 65); transform: translateX(-50px) rotateY(-90deg); }
.right { background: rgb(214, 28, 65); transform: translateX(50px) rotateY(90deg); }
.top { background: rgb(71, 17, 172); transform: translateY(-50px) rotateX(90deg); }
.bottom { background: rgb(217, 44, 124); transform: translateY(50px) rotateX(-90deg); }
把这两个文件放在同一目录下,浏览器打开 HTML,你就能看到一个六面不同色、永动旋转的 3D 立方体。
七、进阶话题:CSS 3D 与 GPU 加速
CSS 3D 的能力不仅是炫技,它还带来了一个实打实的性能红利------GPU 加速。
浏览器的渲染流水线大致是这样:布局(Layout)→ 绘制(Paint)→ 合成(Composite)。
普通的 2D 动画(比如改 left、top、width)会触发重排和重绘,主线程压力很大。但 CSS transform 和 opacity 的动画只影响合成阶段,浏览器会把它丢给 GPU 独立处理,主线程完全不受影响。
这就是为什么很多前端在做 2D 页面时,也会刻意"手动 3D 化"------给元素加一句:
css
.element {
transform: translateZ(0);
/* 或者 */
will-change: transform;
}
这条语句会触发浏览器为该元素创建一个独立的合成层(GraphicsLayer),交给 GPU 渲染。哪怕画面是完全平面的,GPU 加速带来的流畅度提升也是实打实的。
不过也别滥用------每个合成层都会消耗显存,动辄给几百个元素开合成层反而会适得其反。
八、总结
这篇文章从布局基石一路盖到了 3D 楼阁,核心脉络如下:
- Display 体系 :
block/inline/inline-block/flex各司其职,flex 是现代布局首选 - 居中方案 :Flex + 双轴对齐是最优雅的通用解法,
vh/vw单位让移动端适配更简单 - 定位 :
relative建坐标系,absolute叠放 6 个面 - CSS 3D 三件套 :
perspective:控制 3D 透视强度transform-style: preserve-3d:保留子元素的三维空间transform:用translateX/Y/Z平移 +rotateX/Y/Z旋转,把 6 个面拼成立方体
- 动画 :
@keyframes+animation让立方体永动旋转 - GPU 加速:CSS 3D 不仅是视觉效果,更是性能优化的利器
CSS 3D 的潜力远不止一个旋转立方体------翻书效果、3D 轮播图、立体卡片翻转,都是它的经典应用场景。掌握这篇文章里的知识点,你已经有了实现这些效果的全部武器。

本文所有示例代码均为实战验证过的可运行代码,直接复制即可跑通。