CSS 3D 从入门到炫技:手把手教你写一个旋转立方体

前言

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


一、先聊布局:HTML5 的三次进化

在进入 3D 世界之前,有必要把地基打好。CSS 3D 依赖的核心属性(transformperspective)是和布局体系深度耦合的,布局不扎实,后面写 3D 只会一头雾水。

1.1 行内与块级:浏览器的默认剧本

HTML 元素天生分为两派:

类型 代表元素 能设宽高? 会独占一行?
块级 (block) divulp 可以 会,把兄弟元素挤到下一行
行内 (inline) spanaem 不可以 不会,和兄弟元素和平共处

浏览器给你设好了默认值,但你随时可以用 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%htmlbody 默认高度是由内容撑开的,不显式设 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。解决方案是把初始状态写在 @keyframes0% 里。


六、完整代码

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 动画(比如改 lefttopwidth)会触发重排和重绘,主线程压力很大。但 CSS transformopacity 的动画只影响合成阶段,浏览器会把它丢给 GPU 独立处理,主线程完全不受影响。

这就是为什么很多前端在做 2D 页面时,也会刻意"手动 3D 化"------给元素加一句:

css 复制代码
.element {
  transform: translateZ(0);
  /* 或者 */
  will-change: transform;
}

这条语句会触发浏览器为该元素创建一个独立的合成层(GraphicsLayer),交给 GPU 渲染。哪怕画面是完全平面的,GPU 加速带来的流畅度提升也是实打实的。

不过也别滥用------每个合成层都会消耗显存,动辄给几百个元素开合成层反而会适得其反。


八、总结

这篇文章从布局基石一路盖到了 3D 楼阁,核心脉络如下:

  1. Display 体系block / inline / inline-block / flex 各司其职,flex 是现代布局首选
  2. 居中方案 :Flex + 双轴对齐是最优雅的通用解法,vh/vw 单位让移动端适配更简单
  3. 定位relative 建坐标系,absolute 叠放 6 个面
  4. CSS 3D 三件套
    • perspective:控制 3D 透视强度
    • transform-style: preserve-3d:保留子元素的三维空间
    • transform:用 translateX/Y/Z 平移 + rotateX/Y/Z 旋转,把 6 个面拼成立方体
  5. 动画@keyframes + animation 让立方体永动旋转
  6. GPU 加速:CSS 3D 不仅是视觉效果,更是性能优化的利器

CSS 3D 的潜力远不止一个旋转立方体------翻书效果、3D 轮播图、立体卡片翻转,都是它的经典应用场景。掌握这篇文章里的知识点,你已经有了实现这些效果的全部武器。


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

相关推荐
奋斗吧程序媛1 小时前
补充一个小知识点:有关@click.native
前端·vue.js
DJ斯特拉1 小时前
axios快速使用
开发语言·前端·javascript
还有多久拿退休金1 小时前
Ant Design Tree 搜索定位避坑指南:虚拟滚动下如何实现高亮与精准定位
前端·react.js
xingpanvip1 小时前
星盘接口开发文档:本命盘接口指南
android·开发语言·css·php·lua
Hilaku2 小时前
AI 写代码越快,为什么 Code Review 越不能省?
前端·javascript·程序员
sugar__salt3 小时前
从网页小游戏到数据可视化:掌握 HTML5 Canvas 核心能力
前端·信息可视化·html5
北极星日淘3 小时前
前端 i18n 中日双语交互 + 翻译客服接口联动方案|日系海淘平台中文友好化开发实战
前端·交互
現実逃避と3 小时前
WIN10 Edge连续关闭多个标签页导致资源管理器崩溃临时解决办法
前端·edge
HjhIron3 小时前
CSS 3D 世界:从盒子模型到三维空间动画
javascript·css