Front-end: use css to create cool 3d effects - css3d cube

A 3D object (a cuboid) that rotates around an axis. I already have some experience working with css 3d and a solution is starting to come to my mind. I searched for keywords like "css 3d cube" to confirm my idea.

Friends who are interested in technology can add my front-end learning skirt. Learning number: Leaves, 213126486, and discuss progress together~

sharpened shaft

Let me remind you about the browser axis. Not an axis of war, but a digital line .. In a three-dimensional Cartesian coordinate system, we all learn the same axes.

The Cartesian coordinate system of three-dimensional space is an ordered triad of a pair of perpendicular lines (axes), all three axes having a unit of length, and each axis having an orientation.
Wikipedia: Cartesian Coordinate System

The image below shows how to point to the axes in the browser.

A right-handed three-dimensional Cartesian coordinate system with the Z-axis pointing towards the viewer.

A Cartesian coordinate system that points towards the viewer. (Image credit: Wikipedia )

The x-axis is horizontal, the y-axis is vertical, and the z-axis comes out of the screen. The z-axis zero value is on the plane of the screen. Remember this fact.

Clarify perspective

To create a 3D object, I need an element with a perspective view (let's call it a "scene"). Perspective is the depth of the scene and it depends on the size of the objects it contains.

.scene {
  perspective: 800px;
}

If the perspective is too small, objects will be distorted. If it is too large, the 3D effect is reduced to zero.

Also, all objects in the scene have only one perspective. The 3D effect depends on the viewpoint position.

So, how to calculate the angle of view? I found that it depends on the axis of rotation. For the x-axis it's a height value multiplied by 4, it fits, for the y-axis - the width value multiplied by 4. Here is my magic formula:

  const perspective = dimension * 4;

Consider all sides

After determining the perspective, I start to create a 3D object. I chose a cube because it's simple and predictable. The cube element is a regular div with a width and height defined (for example, 200pxand uses relative positioning. It is converted into a property of a 3d object transform-styleproperty by preserve-3d.. it tells the browser to render all nested elements according to the rules of the 3d world .

In my case, the cube has six divs ("sides"), positioned absolutely. The class names correspond to the initial positions of the sides (rear, left, right, up, down, front). Here is the markup:

<div class="scene">
  <div class="cube">
    <div class="side back"></div>
    <div class="side left"></div>
    <div class="side right"></div>
    <div class="side top"></div>
    <div class="side bottom"></div>
    <div class="side front"></div>
  </div>
</div>

By default all sides are one plane, so I need to rearrange them. Here's how it looks:

The resulting css:

.cube {
  position:relative;
  width: 200px;
  height: 200px;
  transform-style: preserve-3d;
}
.side {
  position: absolute;
  width: 200px;
  height: 200px;
}
.back {
  transform: translateZ(-100px);
}
.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);
}

To rotate the cube, I make transforma property of the cube element whose value is to rotate to any angle along the x-axis:

.cube {
  transform: rotateX(42deg);
}

To overcome the shortcomings

As requested, I just rotate the cube, only along the x-axis, so I don't need the left and right sides. I added subtitles to coincide with the initial position of the rest.

I started to rotate the cube and found that the subtitles on the bottom and back were displayed upside down:

To fix this, I rotated each side by 180 degrees, along the x-axis:

.back {
  transform: translateZ(-100px) rotateX(180deg);
}
.bottom {
  transform: translateY(100px) rotateX(270deg);
}

Beyond the screen

I started filling both sides with real content and immediately faced another problem. I need to have some dashed lines showing, but they are blurry and look bad.

I soon realized what the problem was. Remember the 3d TV commercials when the image expanded beyond the screen, my cube was like that.

If you can look at the cube from the left or right, you will see that its center is in the plane of the screen (zero on the Z axis), and the front is off-screen. Hence, it increases vision and blur.

To fix this, I moved the cube on the z-axis, placing the front side on the plane of the screen:

.cube {
  transform:translateZ(-100px);
}

Here is the almost ready cube:

Use magic numbers

I think you've noticed that I used the magic number 100to move along the axis. 100This is half the height of my test cube. Why half the height? Since, this is the radius of the circle, it is on one side of the cube (which is obviously a square).

const offset = dimension / 2;

If I need to rotate the triangular prism, the circle will be engraved on the triangle. In this case, the offset is calculated as follows:

const offset = dimension / (2 * Math.sqrt(3));

blow the cube out

I have to test the results in different browsers in order to consider completing the task.

The pictures I saw online sent me into a state of depression. To see what I'm talking about, first take a look at the example below, your favorite browser. I changed a property that caused the wrong cube to be displayed in internetexplorer.

In fact, internetexplorer does not support this property. transform-stylevaluable preserve-3d.. In the above example, I replaced preserve-3dthe flat..

So, I am sad but not giving up. The problem is the opportunity to learn something new. Also, I took up the challenge.

Find the pivot

I was looking for a way to create a 3d object without using transform-style: preserve-3dand found a useful property: transform-origin.. It is the center point for element transitions. I created an interactive example that will help you understand how it works:

The 3D rotation of the elements in the example is very similar to the front face of the cube, isn't it? That's what I use.

restart

I started doing cubes all over again. I didn't have to interact with the whole scene, so I removed the perspective attribute of the scene element. Also... add it to every 3D transformation, because now each element transforms independently. Also, I set new properties for each facet - transform-originwith a value equal to the position of the cube's center, backface-visibility: hidden.. This is how the style changes:

.scene {

}
.cube {
  position: relative;
  width: 200px;
  height: 200px;
  transform: perspective(800px) translateZ(-100px);
}
.side {
  position: absolute;
  transform-origin: 50% 50% -100px;
  backface-visibility: hidden;
}

I have to put the sides in the right place. Because of the transform-originproperties, I don't need to change them, just rotate around the axis. It's like magic! Let's see how it works:

Here is the css about the side placement:

.back {
  transform: perspective(800px) rotateY(180deg);
}
.top {
  transform: perspective(800px) rotateX(90deg);
}
.bottom {
  transform: perspective(800px) rotateX(-90deg);
}
.front {
  transform: perspective(800px);
}

Here you can see the new cube in action:

The second cube looks and rotates the same as the first. But in this case you need to transform each aspect individually. Maybe not too easy. Especially when you want to control the middle angle of the rotation.

Also, if you open the example in Chrome, you can see that both sides are flashing while rotating. It's frustrating.

In the end, I used two methods to simply experiment in... transform-style: preserve-3d. The first cube is the default. The second cube is for internetexplorer and is not supported preserve-3d.

Harness the power of mathematics

Finally, I had to implement parallax. Typically, it reacts to user actions. It can be the position of the mouse cursor or the scroll bar. But this time, the effect depends on the rotation angle.

So what data do I have. First, the start and end points of the title position, or make it simple, it's offsetup and down from the center of the side. Second, the anglecube rotates.

It took me hours to come up with a formula and then I figured it out. This is what I remember:

Graphs of the sine and cosine functions

Graph of sine and cosine functions. (Image credit: Wikipedia )

With the help of cosine and cosine, I easily figured out that the offset for each title depends on the angle. Here is the formula I got:

const front_offset = offset * sin(angle) * -1;
const bottom_offset = offset * cos(angle);
const back_offset = offset * sin(angle);
const top_offset = offset * cos(angle) * -1;

in conclusion

Mission accomplished, now I can enjoy the result and share it with you. Use the scroll bar or arrow keys to rotate the promo tile. Also, try pulling the upper, lower and right black triangles to manually control the rotation angle (unfortunately, this feature doesn't work in internetexplorer). Looks great doesn't it? Also, the performance is quite high (around 60fps).

I have gained useful experience with CSS 3d and discovered many new and interesting properties. But most importantly, I've come to realize that one never gives up. Most likely, you can find another way to accomplish this task.

I hope you enjoy my story. Friends who are interested in technology can add my skirt. Learning number: Leaves, 213126486, discuss progress together~

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=325390794&siteId=291194637