CSS 实现一个3d魔方

前言

?CSS 实现一个3d魔方,速速来Get吧~

?文末分享源代码。记得点赞+关注+收藏!

1.实现效果

图片
在这里插入图片描述

2.实现步骤

  • 魔方的一面为九个圆角正方形,定义正方形的宽高为–w,九个正方形的直接的间距为–gap,由此可以计算出父容器的宽/高,box-sizing为border-box
图片
在这里插入图片描述
--w: 60px;
--gap: 10px;
--allW: calc(3 * var(--w) + 4 * var(--gap)); 
  • 魔方有六个面,定义六个面中格子的背景颜色,以及六个面的背景色
--c1: #f5e7a1;
--c2: skyblue;
--c3: #fff;
--c4: #97d497;
--c5: #801a1a;
--c6: orange;
--bg: #000;
  • 设置父容器宽高为–allW
<div class="container"></div>
.container {
  width: var(--allW);
  height: var(--allW);
}
  • 添加魔方元素的父元素,宽高与父容器一致,设置 transform-style: preserve-3d,指示元素的子元素应位于 3D 空间
<div class="container">
 + <div class="container-box"></div>
</div>
.container-box {
  border: 1px solid red;
  position: relative;
  width: var(--allW);
  height: var(--allW);
  transform-style: preserve-3d;
}
  • 在container-box添加魔方的其中一面cube-side,absolute定位,宽高与父元素一致,设置一定的圆角,内边距为gap
 <div class="container-box">
 + <div class="cube-side"></div>
 </div>
.cube-side {
 width: 100%;
 height: 100%;
 position: absolute;
 background: var(--bg);
 border-radius: 7px;
 padding: var(--gap);
}
  • 在cube-side中添加一个宫格,设置color为c1,背景色为currentColor

currentColor:

表示元素color属性的计算值。它能让原本不能默认通过属性或子元素继承的颜色属性继承。如果没有设置color就找父元素,一级一级找,直到根元素。

图片
在这里插入图片描述
<div class="cube-side">
 + <div class="cube-grid" style="--c: var(--c1)"></div>
</div>
.cube-side .cube-grid {
  width: var(--w);
  height: var(--w);
  border-radius: calc(var(--w) / 5);
  color: var(--c);
  background: currentColor;
}

为cube-side添加box-shadow,实现剩余的8个宫格(当然你也可以再写8个宫格,实现九宫格布局

box-shadow:

CSS box-shadow 属性用于在元素的框架上添加阴影效果。你可以在同一个元素上设置多个阴影效果,并用逗号将他们分隔开。该属性可设置的值包括阴影的 X 轴偏移量、Y 轴偏移量、模糊半径、扩散半径和颜色。

eg:图片

  • box-shadow添加第二个宫格
图片
在这里插入图片描述
.cube-grid{
  box-shadow: calc(var(--w) + var(--gap)) 0 0 currentColor;
}
  • box-shadow添加第三个宫格
图片
在这里插入图片描述
box-shadow: calc(var(--w) + var(--gap)) 0 0 currentColor, calc(var(--w) * 2 + var(--gap) * 2) 0 currentColor;
  • box-shadow添加第四个宫格
图片
在这里插入图片描述
box-shadow: calc(var(--w) + var(--gap)) 0 0 currentColor,
 calc(var(--w) * 2 + var(--gap) * 2) 0 currentColor,
 0 calc(var(--w) + var(--gap)) currentColor;
  • 按照此规律,实现剩下的宫格
图片
在这里插入图片描述
box-shadow: calc(var(--w) + var(--gap)) 0 0 currentColor,
  calc(var(--w) * 2 + var(--gap) * 2) 0 currentColor,
  0 calc(var(--w) + var(--gap)) currentColor,
  calc(var(--w) + var(--gap)) calc(var(--w) + var(--gap)) currentColor,
  calc(var(--w) * 2 + var(--gap) * 2) calc(var(--w) + var(--gap))
    currentColor,
  0 calc(var(--w) * 2 + var(--gap) * 2) currentColor,
  calc(var(--w) + var(--gap)) calc(var(--w) * 2 + var(--gap) * 2)
    currentColor,
  calc(var(--w) * 2 + var(--gap) * 2) calc(var(--w) * 2 + var(--gap) * 2)
    currentColor;
  • 这样,魔方的其中一面就完成了
  • container-box添加transform旋转
图片
在这里插入图片描述
.container-box {
 + transform: rotate(45deg) rotateY(45deg) rotateZ(45deg);
}
  • 添加第二面cube-side,宫格实现方式一致,添加transform旋转,x方向旋转-180deg,z轴方向偏移为宽的2分之一
图片
在这里插入图片描述
<div class="cube-side side-back">
 + <div class="cube-grid" style="--c: var(--c2)"></div>
</div>
.cube-side.side-back {
  transform: rotateX(-180deg) translateZ(calc(var(--allW) / 2));
 }
  • 添加第三面cube-side,宫格实现方式一致,添加transform旋转,y方向旋转90deg,z轴方向偏移为宽的2分之一
图片
在这里插入图片描述
<div class="cube-side side-right">
 + <div class="cube-grid" style="--c: var(--c3)"></div>
</div>
.cube-side.side-right {
  transform: rotateY(90deg) translateZ(calc(var(--allW) / 2));
 }
  • 添加第四面cube-side,宫格实现方式一致,添加transform旋转,y方向旋转-90deg,z轴方向偏移为宽的2分之一
图片
在这里插入图片描述
<div class="cube-side side-left">
 + <div class="cube-grid" style="--c: var(--c4)"></div>
</div>
.cube-side.side-left {
 transform: rotateY(-90deg) translateZ(calc(var(--allW) / 2));
}
  • 添加第五面cube-side,宫格实现方式一致,添加transform旋转,x方向旋转90deg,z轴方向偏移为宽的2分之一
图片
在这里插入图片描述
<div class="cube-side side-top">
 + <div class="cube-grid" style="--c: var(--c5)"></div>
</div>
.cube-side.side-top {
 transform: rotateX(90deg) translateZ(calc(var(--allW) / 2));
}
  • 添加第六面cube-side,宫格实现方式一致,添加transform旋转,x方向旋转-90deg,z轴方向偏移为宽的2分之一
图片
在这里插入图片描述
<div class="cube-side side-bottom">
 + <div class="cube-grid" style="--c: var(--c6)"></div>
</div>
.cube-side.side-bottom {
 transform: rotateX(-90deg) translateZ(calc(var(--allW) / 2));
}
  • 将第一面z轴方向偏移为宽的2分之一
图片
在这里插入图片描述
<div class="cube-side side-front">
 <div class="cube-grid" style="--c: var(--c1)"></div>
</div>
.cube-side.side-front {
  transform: translateZ(calc(var(--allW) / 2));
}
  • 可以看到,从某些角度可以看见元素后面的颜色,为每面设置backface-visibility: hidden

backface-visibility: 

CSS 属性 backface-visibility 指定当元素背面朝向观察者时是否可见。

图片
在这里插入图片描述
.cube-side {
 + backface-visibility: hidden;
}
  • 去掉刚开始的border辅助线
图片
在这里插入图片描述
.container-box {
 - border: 1px solid red;
}
  • 为container-box添加动画,进行transform旋转
.container-box {
 + animation: rotate 10s infinite alternate;
}
@keyframes rotate {
 0% {
   transform: rotateZ(0deg) rotateX(0deg) rotateY(0deg);
 }
 15% {
   transform: rotateZ(45deg) rotateX(45deg) rotateY(45deg);
 }
 30% {
   transform: rotateZ(45deg) rotateX(90deg) rotateY(90deg);
 }
 45% {
   transform: rotateZ(45deg) rotateX(135deg) rotateY(135deg);
 }
 60% {
   transform: rotateZ(45deg) rotateX(90deg) rotateY(180deg);
 }
 75% {
   transform: rotateZ(45deg) rotateX(45deg) rotateY(225deg);
 }
 100% {
   transform: rotateZ(45deg) rotateX(0deg) rotateY(270deg);
 }
}
  • 在最外层的父容器上添加perspective,改变透视效果,使之变得更加的协调

perspective: 

CSS 属性 perspective 指定了观察者与 z=0 平面的距离,使具有三维位置变换的元素产生透视效果。z>0 的三维元素比正常大,而 z<0 时则比正常小,大小程度由该属性的值决定。

图片
在这里插入图片描述
.container {
 + perspective: 900px;
}
  • 现在我们试着调整一下w和gap,就完成了啦~
图片
在这里插入图片描述
--w: 30px;
--gap: 8px;
  • 当然,颜色也是可以调整的,这里就不在赘述了哈

3.实现代码

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>151.3d魔方</title>
  </head>
  <link rel="stylesheet" href="../common.css" />
  <style>
    :root {
      --bg: #000;
      --c1: #f5e7a1;
      --c2: skyblue;
      --c3: #fff;
      --c4: #97d497;
      --c5: #801a1a;
      --c6: orange;
      --w: 30px;
      --gap: 8px;
      --allW: calc(3 * var(--w) + 4 * var(--gap));
    }
    .container {
      width: var(--allW);
      height: var(--allW);
      perspective: 900px;
    }
    .container-box {
      position: relative;
      width: var(--allW);
      height: var(--allW);
      transform-style: preserve-3d;
      animation: rotate 5s infinite alternate;
    }
    .cube-side {
      width: 100%;
      height: 100%;
      position: absolute;
      background: var(--bg);
      border-radius: 7px;
      padding: var(--gap);
      backface-visibility: hidden;
    }
    .cube-side .cube-grid {
      width: var(--w);
      height: var(--w);
      border-radius: calc(var(--w) / 5);
      color: var(--c);
      background: currentColor;
      box-shadow: calc(var(--w) + var(--gap)) 0 0 currentColor,
        calc(var(--w) * 2 + var(--gap) * 2) 0 currentColor,
        0 calc(var(--w) + var(--gap)) currentColor,
        calc(var(--w) + var(--gap)) calc(var(--w) + var(--gap)) currentColor,
        calc(var(--w) * 2 + var(--gap) * 2) calc(var(--w) + var(--gap))
          currentColor,
        0 calc(var(--w) * 2 + var(--gap) * 2) currentColor,
        calc(var(--w) + var(--gap)) calc(var(--w) * 2 + var(--gap) * 2)
          currentColor,
        calc(var(--w) * 2 + var(--gap) * 2) calc(var(--w) * 2 + var(--gap) * 2)
          currentColor;
    }
    .cube-side.side-front {
      transform: translateZ(calc(var(--allW) / 2));
    }
    .cube-side.side-back {
      transform: rotateX(-180deg) translateZ(calc(var(--allW) / 2));
    }
    .cube-side.side-right {
      transform: rotateY(90deg) translateZ(calc(var(--allW) / 2));
    }
    .cube-side.side-left {
      transform: rotateY(-90deg) translateZ(calc(var(--allW) / 2));
    }
    .cube-side.side-top {
      transform: rotateX(90deg) translateZ(calc(var(--allW) / 2));
    }
    .cube-side.side-bottom {
      transform: rotateX(-90deg) translateZ(calc(var(--allW) / 2));
    }
    @keyframes rotate {
      0% {
        transform: rotateZ(0deg) rotateX(0deg) rotateY(0deg);
      }
      15% {
        transform: rotateZ(45deg) rotateX(45deg) rotateY(45deg);
      }
      30% {
        transform: rotateZ(45deg) rotateX(90deg) rotateY(90deg);
      }
      45% {
        transform: rotateZ(45deg) rotateX(135deg) rotateY(135deg);
      }
      60% {
        transform: rotateZ(45deg) rotateX(90deg) rotateY(180deg);
      }
      75% {
        transform: rotateZ(45deg) rotateX(45deg) rotateY(225deg);
      }
      100% {
        transform: rotateZ(45deg) rotateX(0deg) rotateY(270deg);
      }
    }
  </style>
  <body>
    <div class="container">
      <div class="container-box">
        <div class="cube-side side-front">
          <div class="cube-grid" style="--c: var(--c1)"></div>
        </div>
        <div class="cube-side side-back">
          <div class="cube-grid" style="--c: var(--c2)"></div>
        </div>
        <div class="cube-side side-right">
          <div class="cube-grid" style="--c: var(--c3)"></div>
        </div>
        <div class="cube-side side-left">
          <div class="cube-grid" style="--c: var(--c4)"></div>
        </div>
        <div class="cube-side side-top">
          <div class="cube-grid" style="--c: var(--c5)"></div>
        </div>
        <div class="cube-side side-bottom">
          <div class="cube-grid" style="--c: var(--c6)"></div>
        </div>
      </div>
    </div>
  </body>
</html>

4.写在最后?

看完本文如果觉得对你有一丢丢帮助,记得点赞+关注+收藏鸭 ?
更多相关内容,关注?苏苏的bug,?苏苏的github,?苏苏的码云~

参考链接:

[1]. 苏苏的github(https://github.com/susu-hu/web-effects)

[2]. 苏苏的码云(https://gitee.com/susuhhhhhh/css_demos)

声明:文中观点不代表本站立场。本文传送门:https://eyangzhen.com/46225.html

联系我们
联系我们
分享本页
返回顶部