【CSS魔法】如何使用CSS绘制一个酷炫的立方体
前言
绘制一个正方形,这个很简单,只要给这个元素设置一个相等的宽高即可。
.square {
width: 200px;
height: 200px;
border: solid 1px gray;
}
若要绘制一个立方体呢?这个貌似就不是个简单的事情了。
本文将带大家一起绘制一个立方体以及如何让这个立方体旋转起来。
正方体是什么?
正方体也叫正六边体。它有6个面,每个面的面积都相同。
立方体绘制
要制作3D效果(立方体),首先要知道web浏览器是怎样确定坐标系的,如图:
注意: x轴平行,y轴垂直,z轴指向正对你的屏幕。z轴的零点就是屏幕所在的平面。
正方体有6个面,这六个面在这个3D空间坐标系中都有对应的位置。这也方便我们后面对每一个面进行移动。
HTML结构
<div class="cube-wrap">
<div class="cube">
<div class="front"></div>
<div class="back"></div>
<div class="left"></div>
<div class="right"></div>
<div class="top"></div>
<div class="bottom"></div>
</div>
</div>
在这之前,我们先简单了解以下属性:
1、perspective
决定了z=0平面和用户之间的距离
2、perspective-origin
决定了查看者正在查看的位置
3、transform-style
设置元素的子元素是位于3D空间中还是在元素的平面中被平展。
4、transform-origin
用于设置元素转换的原点
5、transform
允许您旋转、缩放、倾斜或转换元素
想更直观的感受这些属性设置后的效果,可以在MDN查看。
先把公共样式写出来
.cube-wrap {
position: relative;
/* 3D 元素的透视效果 */
perspective: 800px;
/* 规定 3D 元素的底部位置 */
perspective-origin: 50% 100px;
}
.cube {
position: relative;
width: 200px;
transform-style: preserve-3d;
}
.cube div {
position: absolute;
width: 200px;
height: 200px;
}
初始状态,这6个容器是重叠在一起的。
transform-origin
默认值是center center 0
。示意图如下:
这个属性很重要,设置不同的原点,所需要的转换效果不同,所以我们绘制立方体的方法也不止一种。
本文会介绍几种绘制方法。
旋转基线不变
1、先位移再旋转
看个草稿图,便于理解是如何进行3D转换的。
初始状态下,6个面是堆叠在如上图所示的切面位置。通过3D转换方法,将6个面分别移动到对应位置。
.left {
transform: translateX(-100px) rotateY(-90deg);
}
.right {
transform: translateX(100px) rotateY(90deg);
}
.top {
transform: translateY(100px) rotateX(-90deg);
}
.bottom {
transform: translateY(-100px) rotateX(90deg);
}
.front {
transform: translateZ(100px);
}
.back {
transform: translateZ(-100px) rotateY(180deg);
}
大胆发挥你的空间想象能力~
2、先旋转再位移
以左、右面为例
.left {
transform: rotateY(-90deg) translateZ(100px);
}
.right {
transform: rotateY(90deg) translateZ(100px);
}
详细分析:
左面-left
1、先沿Y轴向左旋转90度
到此就很一目了然了~
2、再沿Z轴正方向移动100px
右面-right
1、沿Y轴向右旋转90度
2、再沿Z轴正方向移动100px
其他面的转换思想都一样。
.top {
transform: translateY(100px) rotateX(-90deg);
}
.bottom {
transform: translateY(-100px) rotateX(90deg);
}
.front {
transform: translateZ(100px);
}
.back {
transform: translateZ(-100px) rotateY(180deg);
}
旋转基线改变
1、旋转
此时以原始堆叠面如图红色区域。以下所有的旋转和位移都以这个面作为参考系。
.left {
transform-origin: left center;
transform: rotateY(-90deg);
}
.right {
transform-origin: right center;
transform: rotateY(90deg);
}
.top {
transform-origin: center top;
transform: rotateX(90deg);
}
.bottom {
transform-origin: center bottom;
transform: rotateX(-90deg);
}
.front {
transform: translateZ(200px);
}
.back {
transform: rotateY(180deg);
}
注意:这样制作的立方体在添加旋转动画时,它会以旋转基线的面进行旋转。
2、先旋转再位移
.front {
transform: translateZ(100px);
}
.back {
transform: rotateY(180deg) translateZ(100px);
}
.right {
transform: rotateY(90deg) translateX(100px);
transform-origin: right center;
}
.left {
transform: rotateY(-90deg) translateX(-100px);
transform-origin: left center;
}
.top {
transform: rotateX(-90deg) translateY(-100px);
transform-origin: center top;
}
.bottom {
transform: rotateX(90deg) translateY(100px);
transform-origin: center bottom;
}
这样一个立方体就被制作出来了。
动画
接下来就是让这个立方体动起来吧~
水平方向旋转
.cube {
animation: spin 5s infinite linear;
}
@keyframes spin {
from {
transform: rotateY(0);
}
to {
transform: rotateY(360deg);
}
}
垂直方向旋转
.vertical {
transform-origin: 0 100px;
animation: spin-vertical 5s infinite linear;
}
/* 调整文字正向展示 */
.vertical .top {
transform: rotateX(-270deg) translateY(-100px);
}
.vertical .back {
transform: translateZ(-100px) rotateX(180deg);
}
.vertical .bottom {
transform: rotateX(-90deg) translateY(100px);
}
/* 垂直方向上的动画 */
@keyframes spin-vertical {
from {
transform: rotateX(0);
}
to {
transform: rotateX(360deg);
}
}
其他方向旋转
同时沿水平、垂直方向旋转
.other {
transform-origin: 100px 100px;
animation: spin-other 5s infinite linear;
}
/* 其他方向上的动画 */
@keyframes spin-other {
from {
transform: rotateX(0) rotateY(0);
}
to {
transform: rotateX(360deg) rotateY(360deg);
}
}
开箱动画
场景描述:鼠标移到这个立方体上,最上面的盖子打开,并且里面的小立方体浮动上来。
<div class="cube-wrap">
<div class="cube horizontal">
<div class="front">正面</div>
<div class="back">反面</div>
<div class="top">上面</div>
<div class="bottom">下面</div>
<div class="left">左面</div>
<div class="right">右面</div>
<i class="front">gift</i>
<i class="back">gift</i>
<i class="top"></i>
<i class="bottom"></i>
<i class="left">gift</i>
<i class="right">gift</i>
</div>
</div>
css
/* hover transformations */
.horizontal:hover div.top{
transform: translateZ(100px) rotateX(-210deg);
transform-origin: top center;
}
.horizontal:hover i{
top: -200px;
}
完整代码请看在线demo
结语
这真的考验一个人的空间想象能力,每个面的各种旋转角度,移动方向,真的死了我好多脑细胞。
可以和我之前的一篇flex布局实践篇 | 骰子结合起来实现一个立体的骰子。
小问题:就是骰子每一面设置了圆角,在立体空间中就会造成每一个角上都会有空隙。有什么好的方法解决吗?
参考文章:
转载自:https://juejin.cn/post/7212101184709181497