3D transformations using CSS


Having seen a couple of impressive examples of 3D transformations using CSS tools on the Internet, I became interested, decided to understand the topic, read several articles, and seemed to understand something. But, as you know, a theory without practice - like a zombie - is dead, although it can eat the brain.

To master the material you need to do something interesting yourself using the read. Which three-dimensional object is the easiest to make? Perhaps a cube. And to make the result more interesting and more beautiful, let it be a dice with dots on the edges. Go.

For impatient and those who look Habr for the sake of funny pictures - the end result . Works in Chrome, latest versions of Firefox, Safari. Opera 12.01 - so far, but you yourself know everything about IE.


Building materials


First, we’ll make a blank. A block container to center everything on the page, a block cube in which we will put all the components of our sculpture, and a “sweep” of five (sixth we add later) future faces of the cube.

“Faces” are trivial square divs absolutely positioned in a block-cube: we will leave the “unit” in the center, it will serve as the front side, and we will dock all the others with it, as in Figure 1 . Color them for fun and visualization in different colors, add an inner shadow - and that's enough.

The points on the faces are also blocks with position: absolute, border-radius: 50% and an inner shadow ( box-shadow: inset ...) to give the illusion of volume.

In the end - two not so trivial moments.

For the cube itself, you need to specify

transform-style: preserve-3d; 

otherwise the default value will be used - flat , the three-dimensional world will again become flat and only one face will remain from our cube, which is located “facing” the user.

A small remark: hereinafter, css properties for transformations are indicated without prefixes, but in real code, for now, you need to use them.

Also add a property to the cube

transform: perspective(900px);

which will determine how much it will be distorted due to perspective. The larger the value, the farther the point of “convergence of lines” is, the less pronounced the distortion effect. Values ​​below 200 lead to wild results (for example, Figure 2 ), about 300 - to a noticeable distortion ( Figure 3 ), but we restrict ourselves to a modest 900, giving a very moderate effect.



With the routine finished, the fun begins.

Bend and glue


To turn our scan into a kind of cube, you need to “bend” it along the lines of abutment of the extreme faces to face-1. To do this, we need to do two things.

First, set the axis for each face around which it will rotate. The fact is that, by default, the blocks rotate around their center, and we need a slightly different behavior - in Figure 4 we see that face-5 should rotate around segment AB, face-2 around BC, and so on.

We use the property

transform-origin: y x;

which shifts the axis of rotation for the object. For example, for face-5 you need to move the X axis (horizontal) to the bottom edge, respectively, the second value of transform-origin should be 100% ( transform-origin: 0 100%; ). The value of Y in this case is unimportant, because we will rotate this face exclusively around the horizontal axis. For face-2, the opposite is true - the value of X is unimportant, and Y should be set to 0, i.e. fit transform-origin: 0 0 .

Secondly, and, for this article, "mainly", for the direct rotation of the elements we use

transform: rotate3d(x, y, z, deg);

The first three parameters determine which of the coordinate axes the object will rotate, and the last - by how many degrees. X, Y and Z are not defined as absolute values, but as a ratio of angles. For example, transform code : rotate3d (2, 1, 0, 90deg); causes the object to rotate 90 degrees around the X axis and 45 (90 * 1/2) degrees around Y. The transform: rotate3d (90, 45, 0, 90deg) line will do the same .

In Figure 5, I tried to illustrate the rotation of the blocks around the axes: a gray rectangle is the initial position of the block, the axis around which the rotation is highlighted in red, red and green rectangles are the position of the block when rotated by -60 and 60 degrees, respectively.



We rotate the second to fifth faces 90 degrees around the corresponding axes, after which, for clarity, we rotate the cube itself, adding the transform: rotate3d (1,2,0, -150deg) property to .cube , resulting in something that is depicted in figure 6 . The cube is almost ready, it remains only to "close" it.



Close the lid and serve.


The last face should be placed in the same place as the “unity”, but “deeper” into the screen by 200px (the size of the faces of the cube). Let's do it using the property

transform: translate3d(x, y, z);

which allows you to move the block along any of the three axes. In our case, the movement along the Z axis is minus 200 pixels (negative values ​​“delete” the block, positive values ​​“zoom in”). At the same time, we rotate the face 180 degrees along the X axis - although, with default values, the “dots” will be displayed on both sides, it would be more correct to place the face with its face towards the viewer, and not inside the cube. As a result, the transform property for our “cover” will look like this: transform: translate3d (0,0, -200px) rotate3d (1,0,0,180deg) .

Finally, using the banal opacity: 0.9, let's add a bit of transparency (for Firefox, for some reason I haven’t clarified, only adding this property to individual faces works, but not to the whole block cube right away) - this way our cube becomes a bit like glass, looks more presentable and, to be honest, calls the author had a fit of warm nostalgia for the time when the “computer” was an incomprehensible machine for dad at work, and a similar dice acted as a generator of pseudorandom numbers in many games.

Let's rock, let's roll


The cube is ready, but to look at it from the other side, you need to climb and edit CSS - not the most user-friendly option, frankly. We will act differently.

At the beginning of the container block (before the cube), add four buttons:

Again, using absolute positioning, we will arrange them on all four sides of the container, after which we will make the cube rotate using about the following magic:
.a-top:hover ~ .cube    {
     transform: perspective(900px) rotate3d(180,-45,0,-135deg);           
}      

The “~” selector, in contrast to the “+”, applies not only to the immediate neighbor, but also to the “farther” ones, as long as they are at the same level in the DOM tree, which we use. When you hover over the .a-top button, we will rotate the next .cube block after it the way we want.

At the same time, we will change the perspective distortion using perspective (900px). As you recall (remember, right?), We set the same value for the cube at the beginning of the work, but if you do not declare this property again after the cube is back to us, and to the forest (on the desktop wallpaper) before, then and this distortion will turn out together with the cube - the part closest to the viewer will be reduced, and the distant part will be expanded. It looks implausible, so we will assign perspective again at each turn.

Well, so that our cube does not jump from one position to another, but rotates smoothly - add a line to it

transition: all 1s ease;

Translated into Russian - let's say a cube smoothly change all the properties ( all ) that will change within one second ( 1s ) and do this using the ease function , i.e. at the beginning of the animation, smoothly accelerate it, and at the end - smoothly stop it. Fans of uniformity instead of ease can specify linear - in this case, the cube will move tediously and soullessly.

However, Houston, we have another problem. The rotation goes around the center of face-1, and not the center of the cube itself - which, in general, is logical, because we have it inscribed in the block cube, and all the rest are “bent” or moved “deep”. However, this is solved quite simply: you just need to “move” all the faces closer to the observer using the sametranslate3d (0,0,100px) so that the center of rotation coincides with the center of the cube.

Now it turned out pretty well. You can write an article on Habr to consolidate the material, share what you have learned with colleagues and just show off.

Link to the demo
Archive for the most curious

PS While writing an article and making my way into the sandbox, a similar article has already appeared on the hub , but I think they will complement each other well.

Update:
Important additions from zapimir
- 3DTransform is just a draft, not a standard, changes
are possible - IE10 supports this technology (fixed demo, added prefixes -ms- )
- It’s convenient to follow the progress of the planet on caniuse.com - in particular, here

Also popular now: