CSS 3D 讲解 —— 写一个旋转正方体(含示例)

1,995 阅读7分钟

文本示例见:www.risu-p.com/planet/#/3d

一、CSS 3D 基础知识

先对 3D 基础知识进行概览讲解

再对相关属性进行详细说明

1.1 使用 transform-style 启用 3D 模式

要使用 CSS3 实现 3D 效果,主要是借助 transform-style 属性。 transform-style 只有两个值可以选择:

// 语法:
transform-style: flat|preserve-3d;
 
transform-style: flat; // 默认,子元素将不保留其 3D 位置
transform-style: preserve-3d; // 子元素将保留其 3D 位置

当指定一个容器的 transform-style 属性值为 preserve-3d 时,容器的后代元素便会具有 3D 效果。即当容器设置了 preserve-3d 后,它的子元素就可以相对于父元素所在的平面,进行 3D 变形操作

但仅设置transform-style,并不能实现我们所希望看到的立体效果。为了在屏幕上看见 3D 效果的图形,还需继续设置观察者位置

1.2 利用 perspectiveperspective-origin 设置 观察者 位置,实现景深效果

perspectiveperspective-origin用于设置观察者位置:即从哪个位置(距离和角度)来看我们的 3D 图形

transform-style一样,设置于容器(父)元素上

perspective

当元素没有设置 perspective 时,所有后代元素被压缩在同一二维平面上,不存在景深的效果

image.png

而设置 perspective 后,将会看到三维效果

// 语法
perspective: number|none;

例:下图为一正方体图形,设置perspective后,出现了景深效果(正面更靠近观察者,故更大)

image.png

perspective: 400px;

perspective-origin

perspective-origin 表示观察者视角的位置

默认视角基点是 perspective 所在元素的中点,也就是 perspective-origin: 50% 50%

通过修改perspective-origin可以实现从不同角度观察 3D 图形(例如从右上角观察)

// 语法
perspective-origin: x-axis y-axis;
// x-axis : 定义该视图在 x 轴上的位置。默认值:50%
// y-axis : 定义该视图在 y 轴上的位置。默认值:50%

下图即为在 z轴正向400px处、右上方 观测到的正方体: Xnip2022-02-08_16-49-56.jpg

transform-style: preserve-3d;
perspective: 400px;
perspective-origin: 200px -100px;

二、3D 相关属性

依次阅读下文与 3D 相关的属性,将对css的 3D 坐标系有一个清晰的认识

以下图背景色 rgba(0,0,0,0.8),包含一个正方形的情况为例:

image.png

2.1 transform-style

设置于容器(父)元素上

设置元素的子元素是位于 3D 空间中还是平面中

如果选择平面,容器的子元素将不会有 3D 遮挡关系

该属性不会被继承

// 语法:
transform-style: flat|preserve-3d;
 
transform-style: flat; // 默认,子元素将不保留其 3D 位置
transform-style: preserve-3d; // 子元素将保留其 3D 位置

2.2 rotateX()

x轴旋转

x轴

轴线方向:左右横向的一条轴线(向右为正)

旋转方向:顺时针

transform: rotateX(30deg);

image.png

可见 上部分 被旋转到了平面后方

2.3 rotateY()

y轴旋转

y轴

轴线方向:上下竖直的一条轴线(向下为正)

旋转方向:顺时针

transform: rotateY(30deg);

image.png

可见 右侧 被旋转到了平面后方

2.4 rotateZ()

z轴旋转

z轴

轴线方向:垂直于屏幕(贯穿屏幕)的一条轴线(向外为正)

旋转方向:顺时针

transform: rotateZ(30deg);

image.png

2.5 translateX()

沿x轴移动

transform: translateX(30px);

image.png

注意:

css坐标系,是变化坐标系

移动后,变换坐标原点仍然在元素中心(默认);即向右移动20px,坐标系也跟着移动了20px

旋转时也是如此,元素旋转,坐标轴也一并跟着旋转

后文对transform顺序讲解中,也有说明

2.6 translateY()

沿y轴移动

transform: translateY(30px);

image.png

2.7 translateZ()

沿z轴移动

# 注意这里设成了负数
transform: translateZ(-30px);

image.png

设为负数后,正方形移动至平面后方了

但现在不论如何改变 translateZ 正方形大小看上去并不会改变(即没有景深效果),因为我们没有设置观察者位置

想实现景深效果(即z越远,看起来越小),需要用到 perspective 属性

2.8 perspective

transform-style一样,设置于容器(父)元素上

指定观察者与z=0屏幕的距离,使具有三维位置变换的子元素产生透视(景深)效果

当值为0或负值时,无透视变换

三维元素在观察者后面的部分不会绘制出来

# 语法
/* Keyword value */
perspective: none;


/* <length> values */
perspective: 20px;
perspective: 3.5em;


/* Global values */
perspective: inherit;
perspective: initial;
perspective: unset;
# 示例
transform-style: preserve-3d;
perspective: 400px;

image.png image.png

可见离观察者越近的元素,看起来越大

注意:

我们人眼在屏幕上看见的,即屏幕上显示的画面 —— 其实是元素相对于观察者,在屏幕上的的投影

详见下文【疑问: translateZ 为负数时,观察者越远,元素反而越大了?】

2.9 perspective-origin

transform-style一样,设置于容器(父)元素上

perspective-origin 指定了观察者的位置(类似transform-origin),默认为容器中心

下面 MDN 的示例展示了,从右下方观察 3D 正方体:

image.png

2.10 backface-visibility

设置在变化(子)元素上

backface-visibility属性定义当元素后面是否可见

# 语法
backface-visibility: visible|hidden;

以下示例为6面都透明的正方体,按正常理解,每面都透明,就可以看到后面

但如果设置 backface-visibility: hidden ,即使面的背景色为透明,也看不见其后面的元素(此时,透明度仅影响那一面的色值)

image.png

三、3D属性的一些易混淆点

3.1 translateZ 为负数时,观察者越远,元素反而越大?(元素的投影)

2.7中,对translateZ进行了介绍,它指定了元素在z轴上的移动距离

2.8perspective进行了介绍,它设置了观察者距离z=0的距离,以实现景深效果

设想一种情况:有一 translateZ(10px) 的元素,我们移动观察者位置 perspective: 30pxperspective: 500px。那么观察者越靠近元素,元素看上去应该越大。即perspective: 30px 时,元素看上去应比 perspective: 500px 时大

事实也是如此:

image.png image.png

但当我们将 translateZ 设为负数时,情况就发生了变化。若将 translateZ 设为负数,perspective: 30px 时,元素在屏幕上显示的大小比 perspective: 500px 时小!

image.png image.png

这是因为,屏幕上显示(即我们肉眼看见的),其实是元素的投影

image.png

translateZ 为正时:

image.png

translateZ为正时,观察者越远,元素照在屏幕上的投影越小(屏幕上的投影才是我们人眼看见的,上图中的“眼睛”指的观察者)

所以,观察者再远,投影大小也不会小于元素本身大小

观察者非常近,投影就会无限大

观察者在元素背面,则没有投影

translateZ 为负时:

image.png

translateZ为负时,观察者越远,元素在屏幕上的投影越大!

试想,观察者就贴着屏幕,那投影就只能覆盖屏幕上1px区域

所以观察者越远,元素越大,但怎么也不会大于元素本身

观察者非常近(指非常靠近屏幕,因为观察者大于0才是有效值),元素则小到基本消失

3.2 transform 多值组合时,有顺序关系吗?

有!

transform: rotateX(180deg) translateZ(50px);

transform: translateZ(50px) rotateX(180deg);

不一样

css 坐标系是变化坐标系,不论元素做何变化(旋转、位移、倾斜等),坐标系也会跟着元素变化。即元素沿x移动了10px,坐标系也会跟着移动

坐标原点始终在元素中点位置(默认,其实是在transform-origin指定的位置)

而当多值组合时,从左至右执行(记住 每次执行,坐标轴也会一起变化)

以上,就是本次讲解的 CSS 3D 的所有了,让我们灵活运用吧!