One time when the boss was playing King of Glory, he happened to see that king of Glory had a cool effect of rubik’s cube (I can’t find the picture now), so he asked us to put the cube into the project. King of Glory is 3d, so aren’t we overusing WebGL for a Rubik’s Cube effect? Then I tried to use pure CSS to implement a Rubik’s cube, and I got the following effect, which is not satisfactory compared to real 3D.

Results show

GIF image effect display:

Online effect display: pseudo-3D Rubik’s Cube

Make a rubik’s cube

Next, start making rubik’s cube

Implement a single cube

Look carefully at our second order Rubik’s cube, it is composed of 8 small squares, so our first step is to achieve a small square. The cube has six sides, so we can use six divs to make a cube.

  <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>
Copy the code

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); // To make it easier to see the three sides of the small box
    background: white;
  }
Copy the code

Style the face div of the small box

.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;
  }
Copy the code

This should look like the image below, with the six divs now stacked on top of each other.

Now let’s change the position of the six faces. Let’s use the before face as the reference plane, and all the rest of the changes are relative to the before face. Set before surface:

  .cube-before {
    left: 0;
    top: 0;
  }
Copy the code

Then set the after face, which has two transformations relative to the before face:

  • It’s moving along the z-axis$width
  • Relative to thexThe axis is flipped 180 degrees
  .cube-after {
    left: 0;
    top: 0;
    transform: translateZ(-$width) rotateX(180deg);
  }
Copy the code

Set to the following effect:

Similarly, we set up the up side and down side:

  .cube-up {
    left: 0;
    top: -$width;
    transform: rotateX(90deg);
    transform-origin: bottom;
  }
  .cube-down {
    left: 0;
    top: $width;
    transform-origin: top;
    transform: rotateX(-90deg);
  }
Copy the code

Then set the left side and right side:

 .cube-left {
    left: -$width;
    top: 0;
    transform-origin: right;
    transform: rotateY(-90deg);
  }
  .cube-right {
    right: -$width;
    top: 0;
    transform-origin: left;
    transform: rotateY(90deg);
  }
Copy the code

So we have a single cube.

Glowing effect

You want the squares to glow a little bit, so give div borders a fluorescent green color, and use the pseudo-elements :before and :after for each face div to create a light effect at each corner. In addition, the text can also be hidden, so let’s make it transparent.

  .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; }}Copy the code

Plus the effect of light:

It’s not like a cube.

Let’s rotate it around and see

  .cube-inner{...animation: xuanzhan 10s linear infinite;
  }
   @keyframes xuanzhan {
    0% {
      transform: rotateX(0deg) rotateY(0deg);
    }
    100% {
      transform: rotateX(360deg) rotateY(360deg); }}Copy the code

B: well… Every side is square.

Realize the second order Rubik’s cube

The second order rubik’s cube is composed of 8 such small squares, a small square is a component (Magic), then we quote 8 times, and then adjust the position of each can achieve the desired effect

  <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>
Copy the code

Use absolute positioning to adjust the position, the distance looks appropriate is about the same

.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;
  }
Copy the code

Effect:

Realize the dynamic effect of rubik’s cube

We added two dynamic effects to the rubik’s cube

  • Its rotation
  • Set two of the small squares to expand outward and then retract

Self rotation was mentioned above

.magic-container{
    animation: xuanzhan 30s linear infinite;
    transform-style: preserve-3d;
}
@keyframes xuanzhan {
  0% {
    transform: rotate(0deg);
  }
  100% {
    transform: rotate(360deg); }}Copy the code

The animation of small squares is also relatively simple:

  .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); }}}Copy the code

Implementing flow lines

The principle of line flow effect is also very simple, is to use div to achieve two circles rotation effect. Let’s start by drawing a glowing circle:

 <div class="cir cir1" />
 <div class="cir cir2" />
Copy the code
  $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;
  }
Copy the code

Then use the mask-image property to give it a gradient effect

mask-image: linear-gradient(0deg.rgba(white, 0.9) 0%.rgba($lightBg, 0.7) 30%.rgba($bg, 0));
Copy the code

Then add the transform properties and animations:

 .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); }}Copy the code

Likewise 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); }}Copy the code

The final effect is formed

The code address

Demo written using Vue, complete code on Github: Rubik’s cube code

Finally, thanks to the screen recording function provided by WPS, it is very easy to use for the first time