preface

Some time ago, WHEN I queried MDN, I found that there was an experimental property called transform-style in CSS, which was used to set whether the child elements of an element were located in 3D space or plane, which was also the key to realizing 3D cube. So since it is an experimental function, there will naturally be compatibility problems, and then found 🙄

Final effect display

Implementation approach

Rendering a cube requires six faces, up and down, left, right, front and rear, each representing a div. Here we use pseudo-class elements to set the two elements up and down, because the left, right, front and rear faces are 90deg, so we use CSS variables to control the rotation of their angles. Now we need to set transform-style: preserve-3d on the parent element; This allows the child elements to reside in 3D space. The four faces are combined by the rotation of the Y-axis, and the upper and lower elements are set by a div element and pseudo-class element. Don’t forget to translateZ() defines the 3D transformation of the Z-axis. Finally, there is the animation of rotation, the rotation of 360deg in the Y direction, and the rotation of X axis by a certain Angle in the opposite direction of the coordinate system. Only one direction of rotation is the rotation of the plane.

Code sample

//HTML
 <body>
    <div class="cube">
      <div class="top"></div>
      <div>
        <span style="--i: 0"></span>
        <span style="--i: 1"></span>
        <span style="--i: 2"></span>
        <span style="--i: 3"></span>
      </div>
    </div>
 </body>
Copy the code
//CSS
* {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

body {
  display: flex;
  min-height: 100vh;
  overflow: hidden;
  justify-content: center;
  align-items: center;
  background: #050505;
}

.cube {
  position: relative;
  width: 300px;
  height: 300px;
  transform-style: preserve-3d;
  animation: animate 4s linear infinite;
}

@keyframes animate {
  0% {
    transform: rotateX(-30deg) rotateY(0deg);
  }
  100% {
    transform: rotateX(-30deg) rotateY(360deg);
  }
}

.cube div {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  transform-style: preserve-3d;
}

.cube div span {
  position: absolute;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: linear-gradient(#151515, #00ec00);
  transform: rotateY(calc(90deg * var(--i))) translateZ(150px);
}

.top {
  position: absolute;
  top: 0;
  left: 0;
  width: 300px;
  height: 300px;
  background: #222;
  transform: rotateX(90deg) translateZ(150px);
}

.top::before {
  content: "";
  position: absolute;
  top: 0;
  left: 0;
  width: 300px;
  height: 300px;
  background: #0f0;
  transform: translateZ(-380px);
  filter: blur(20px);
  box-shadow: 0 0 120px rgba(0.255.0.0.2), 0 0 200px rgba(0.255.0.0.4),
    0 0 300px rgba(0.255.0.0.6), 0 0 400px rgba(0.255.0.0.8),
    0 0 500px rgba(0.255.0.1);
}

Copy the code

Summary of Attention points

  1. transform-styleIn official usage there areflat | preserve-3d.flatSet the element’s children to be in the plane of the element. The children of the element will not have a 3D occlusion relationship.preserve-3dThe children of the specified element are in 3D space. Note that this attribute is not inherited, so it must be set for all non-leaf child elements of the element.
  2. CSS declarations of variables are preceded by two horizontal lines (–), such as — I in code.$is used in Sass and @ is used in Less. It is worth mentioning that variable names are case-sensitive.var()Functions are used to read variables, such as in codevar(--i)The function can also accept a second value as the default value for the variable, which will be used if the variable does not exist.var()Functions can also be used for variable declarations, but variable values can only be used for attribute values, not attribute names.
// The correct way
.root{
    --primary-color:green;
    --i:var(--primary-color);
}
// Error
.root{
    --primary-color:background-color;
    --i:var(--primary-color);
}
Copy the code

3. If CSS variables are numeric values, they cannot be used directly with numeric units. They must be connected using the calc() function. For example, calc(90deg * var(– I)) in code. If the variable value has units, it cannot be a string.

// The correct way
.root{
    --primary-size:20;
    margin-top:calc(var(--primary-size)*1px);
}
.root{
    --primary-size:20px;
    margin-top:var(--primary-size);
}
// Error
.root{
     --primary-size:20;
    margin-top:var(--primary-size)px;
}
.root{
    --primary-size:'20px';
    margin-top:var(--primary-size);
}
Copy the code