有次老板在打王者荣耀,正好看到王者荣耀有个魔方的炫酷效果(现在找不到图了),就让我们把这魔方搬到项目中。王者荣耀那是三维的啊,我们为了一个魔方效果就用webgl,岂不有点大材小用?然后就尝试着用纯css去实现一个魔方,接着就有了下面这样的效果,相比真正的三维,只能说差强人意吧。
效果展示
gif图片效果展示:
线上效果展示:伪3D魔方
制作魔方
接下来就开始制作魔方
实现单个小方块
仔细看我们这个二阶魔方,是由8个小方块组成的,所以我们第一步是先实现一个小方块。小方块有6个面,所以我们可以用6个div来拼成一个小方块。
<div class="cube-inner">
<div class="cube-face cube-up">up</div>
<div class="cube-face cube-down">down</div>
<div class="cube-face cube-left">left</div>
<div class="cube-face cube-right">right</div>
<div class="cube-face cube-before">before</div>
<div class="cube-face cube-after">after</div>
</div>
设置容器为3d舞台transform-style: preserve-3d;
$width: 80px;
$color: #02FFF6;
$color1: #98fdf0;
$lightColor: #B6FFF5;
.cube-inner {
width: $width;
height: $width;
position: relative;
transform-style: preserve-3d;
transform: rotateX(20deg) rotateZ(45deg); // 为了方便看到小方块三面
background: white;
}
给小方块的面div设置样式
.cube-face {
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(0deg, rgba($color,0.7),rgba($color1,0.8));
text-align: center;
line-height: $width;
}
设置完就是下图这样的效果,6个div现在重叠在一起。
现在就开始变换6个面的位置,我们以before面为参考面,后面所有面的变换都是相对于before面的。设置before面:
.cube-before {
left: 0;
top: 0;
}
然后设置after面,after面相对于before面有两个变换:
- 在z轴上移动
$width - 相对于
x轴翻转180度
.cube-after {
left: 0;
top: 0;
transform: translateZ(-$width) rotateX(180deg);
}
设置完为如下效果:
同理,我们设置up面和down面:
.cube-up {
left: 0;
top: -$width;
transform: rotateX(90deg);
transform-origin: bottom;
}
.cube-down {
left: 0;
top: $width;
transform-origin: top;
transform: rotateX(-90deg);
}
然后再设置left面和right面:
.cube-left {
left: -$width;
top: 0;
transform-origin: right;
transform: rotateY(-90deg);
}
.cube-right {
right: -$width;
top: 0;
transform-origin: left;
transform: rotateY(90deg);
}
这样我们单个小方块就制作完成了。
发光效果
想要小方块有点发光的效果,所以给div的边框颜色设置成荧光绿,并且利用每个面div的伪元素:before和:after在每个角制作出光效。此外文字也可以隐藏了,我们就设置为透明色。
.cube-face {
position: absolute;
width: 100%;
height: 100%;
background: linear-gradient(0deg, rgba($color,0.7),rgba($color1,0.8));
background-blend-mode: screen;
border: 1px solid $lightColor;
box-shadow: inset 0 0 2px rgba($lightColor, 1), 0 0 2px rgba($lightColor, 1);
color: transparent;
&::before,
&::after {
content: '';
position: absolute;
top: -2px;
width: 10px;
height: 10px;
border-color: $lightColor;
border-style: solid;
border-top-width: 2px;
border-bottom-width: 0;
box-shadow: inset 0 0 8px rgba($lightColor, 1), 0 0 8px rgba($lightColor, 1);
}
&::before {
left: -2px;
border-left-width: 2px;
border-right-width: 0;
}
&::after {
right: -2px;
border-left-width: 0;
border-right-width: 2px;
}
}
加上光效后的效果:
不像个正方体??
我们让它旋转起来再看
.cube-inner {
...
animation: xuanzhan 10s linear infinite;
}
@keyframes xuanzhan {
0% {
transform: rotateX(0deg) rotateY(0deg);
}
100% {
transform: rotateX(360deg) rotateY(360deg);
}
}
嗯...每一面都是方的。
实现二阶魔方
二阶魔方由8个这样的小方块组成,一个小方块是一个组件(Magic),那我们引用8次,再调整每个的位置就能达到想要的效果了
<div class="magic-container">
<Magic class="magic0" />
<Magic class="magic1" />
<Magic class="magic2" />
<Magic class="magic3" />
<Magic class="magic4" />
<Magic class="magic5" />
<Magic class="magic6" />
<Magic class="magic7" />
</div>
用绝对定位来调整位置,距离看着合适就差不多了
.magic0 {
top: -40%;
left: 10%;
z-index: 4;
}
.magic1 {
top: -4%;
left: -28%;
z-index: 10;
}
.magic2 {
top: -4%;
left: 48%;
z-index: 10;
}
.magic3 {
top: 30%;
left: 10%;
z-index: 10;
}
.magic4 {
top: -20%;
left: 10%;
z-index: 2;
}
.magic5 {
top: 16%;
left: -28%;
z-index: 4;
}
.magic6 {
top: 16%;
left: 48%;
z-index: 4;
}
.magic7 {
top: 50%;
left: 10%;
z-index: 4;
}
效果图:
实现魔方动态效果
我们给魔方加了两个动态效果
- 自身旋转
- 设置其中两个小方块向外扩展然后收回 自身旋转我们在上面已经提到过了
.magic-container{
animation: xuanzhan 30s linear infinite;
transform-style: preserve-3d;
}
@keyframes xuanzhan {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
小方块的动画也比较简单:
.magic2 {
top: -4%;
left: 48%;
z-index: 10;
animation: translateMove1 10s infinite;
@keyframes translateMove1 {
0%,
60%,
100% {
transform: translateX(0) scale(0.6);
}
6%,
40% {
transform: translateX(24%) scale(0.7);
}
}
}
.magic3 {
top: 30%;
left: 10%;
z-index: 10;
animation: translateMove 10s infinite -4s;
@keyframes translateMove {
0%,
60%,
100% {
transform: translateY(0) scale(0.6);
}
8%,
50% {
transform: translateY(24%) scale(0.7);
}
}
}
实现流动线条
线条流动效果的原理也非常简单,就是用div实现的两个圆旋转的效果。 我们首先画个发光的圆:
<div class="cir cir1" />
<div class="cir cir2" />
$angleX: 64deg;
$angleY: 20deg;
$bg: #02fff6;
$lightBg: #b6fff5;
.cir {
width: 230px;
height: 230px;
border: 4px solid $lightBg;
border-radius: 50%;
box-shadow: 0 0 16px rgba($bg, 0.6), 0 0 16px rgba($bg, 0.6) inset, 0 0 10px $lightBg, 0 0 10px $lightBg inset;
}
然后利用mask-image属性,让它有种渐变的效果
mask-image: linear-gradient(0deg, rgba(white, 0.9) 0%, rgba($lightBg, 0.7) 30%, rgba($bg, 0));
然后再添加变换属性和动画效果:
.cir1 {
animation: rotate 16s -3s infinite linear alternate;
}
@keyframes rotate {
0%,
100% {
transform: rotateX($angleX) rotateY($angleY) rotate(0deg);
}
50% {
transform: rotateX($angleX) rotateY($angleY) rotate(360deg);
}
}
同样cir2也是:
.cir2 {
transform: rotateX($angleX) rotateY(-$angleY);
animation: rotate1 16s infinite linear;
}
@keyframes rotate1 {
0%,
100% {
transform: rotateX($angleX) rotateY(-$angleY) rotate(0deg);
}
50% {
transform: rotateX($angleX) rotateY(-$angleY) rotate(360deg);
}
}
最终效果就形成了
代码地址
demo使用vue写的,完整代码放在github上了:魔方代码
最后感谢WPS提供的屏幕录制功能,第一次用感觉超好用~~