I would like to animate things in 3D space. I know this is possible with CSS and HTML5, but I can't find a good tutorial for practical use!
I found this website as an example. You can select text etc. All the time. Can somebody give a very easy to understand and little example how this works? I see the source code but I don't really understand it…
Is this CSS3 or HTML5 or both?
How much JavaScript do I need?
Which browsers support this?
There are two parts to this.
I'll go through each one of them in detail, but first I'll briefly answer the three questions you've asked at the end.
It's CSS3. CSS 3D transforms and keyframe animations.
Well, if you don't want to create 3D shape itself with JavaScript, then you don't need any JavaScript to animate it. Any browser that supports 3D transforms also supports keyframe animations and, if a browser supports keyframe animations, then you probably want to use those instead of jQuery (and maybe even your own custom JS) animations.
Things didn't look good two years ago, but they're getting better...
✓ Chrome, Safari, Firefox (though Firefox 3D animations are jiggly and not nice to my CPU... I do have a 6-year-old old laptop, it's true) Opera 15+ (WebKit) support 3D transforms. And of course keyframe animations.
Firefox supports everything unprefixed, Chrome/Safari/Opera need the
-webkit-
prefix - update: Chrome 36+ and Opera 23+ support them unprefixed as well, so it's only Safari left now. I won't be using any prefixes in the answer or in the demo (-prefix-free
takes care of things there). Another update: Safari 9 unprefixes transforms.✗ 3D transforms were not supported by Opera before switching to WebKit.
✗ IE up to and including 9 don't support 3D transforms. IE10 and IE11 support 3D transforms, but do not support nesting of 3D transformed elements (cannot create realistic looking 3D shapes via applying 3D transforms on both parent and child elements, as 3D transformed children of a 3D transformed parent get flattened into the plane of the parent). Update: Edge now supports nesting of 3D transformed elements.
Alright, I hope that clears a few things. Now...
1 Building a CSS cube.
1.2 What is a cube and starting off with the HTML
First of all, try to picture a cube. Maybe this link helps? Or let's have an image here as well.
It has 6 square faces. 1 top, 1 bottom; 1 in front, 1 in the back; 1 left, 1 right. This means that the HTML is simply:
You first put some regularity into the faces, give them equal
width
andheight
, position them absolutely so that they're all stacked one on top of the other, give them different backgrounds, they don't mind that. You can give them some padding, put some dummy text into them, whatever...Now comes the interesting part: moving them so that they form a cube in space. You do that using 3D transforms.
1.2 The Coordinate System
Consider this 3D coordinate system:
Initially, all the 6 faces are all exactly where you see the blue square, in the
xOy
plane (whereO
is the intersection of the 3 axes).Pay attention to the direction of the
y-axis
. Coming from a mathematical background, this seemed a bit weird to me at first, but this is how the coordinate system is for the screen.In 2D, the origin
O
is at the top left corner, so the+
(positive direction) of thex-axis
points right and the+
of they-axis
points down.1.2.a Translations along the axes
So a translation of a positive value along the
x-axis
(for example,translateX(10px)
) moves the element to which it is applied to the right (towards the+
of thex-axis
), while a translation of a negative value along thex-axis
(something liketranslateX(-10px)
) moves it to the left.Similarly, a translation of a positive value along the
y-axis
(liketranslateY(10px)
) moves the element down (towards the+
of they-axis
), while a translation of a negative value along they-axis
(liketranslateY(-10px)
) moves it up.Now add another dimension. With the
z-axis
. The+
(positive direction) of thez-axis
comes out of the screen, towards you. So a translation of a positive value along thez-axis
(liketranslateZ(10px)
) moves the element forward (towards the+
of thez-axis
and towards you), while a translation of a negative value along thez-axis
(liketranslateZ(-10px)
) moves it backward (away from you).1.2.b Rotations around the axes
Rotations of positive angle values (for example,
rotate(15deg)
- note that if the rotation axis is not specified, then it is assumed to be thez-axis
) in CSS are clockwise and rotations of negative angle values (likerotate(-15deg)
) are counter-clockwise.And clockwise means clockwise as seen from the
+
of the axis around which you rotate the element.So a positive rotation around the
x-axis
means a clockwise rotation in theyOz plane
as seen from the+
of thex-axis
, which is at the right.A positive rotation around the
y-axis
means a clockwise rotation in thezOx plane
(the horizontal plane) as seen from the+
of they-axis
, which is at the bottom.A positive rotation around the
z-axis
means a clockwise rotation in thexOy plane
(the plane of the screen) as seen from the+
of thez-axis
, which is how you naturally see the screen.1.3 Put the faces in the right positions in order to form the cube
1.3.1 Put one face at the front
This means translating it forwards (in the positive direction) along the
z-axis
. What is this? AtranslateZ
of a positive value. What value? Well, it should be half thewidth
(or theheight
, doesn't matter, it's a square, they're equal).Suppose I have the
width: 16em;
Then in this case, you translate the face forward (along the positive
z-axis
) by16em/2 = 8em
. In CSS, that'sNote: The translate
transform
moves the entire coordinate system of the element that is translated (and consequently, thetransform-origin
for any subsequent transforms).1.3.2 Put the second face at the back
That's simple, right? Just a translate along the
z-axis
, by the same value in the opposite direction, right?.face:nth-child(2) { transform: translateZ(
-8em
); }
, right?Well... actually... only if you don't want to put any content on that face. Or if you don't want to have as a background an image for which it matters which is left and which is right.
Each of these squares that make up the cube has a front and a back. The front is the one towards the positive direction of the
z-axis
; the one that "looks at you from the computer screen". If you put text there, it flows normally on the front. But it looks vertically mirrored on the back.That's why the first thing that you should do is to rotate the second square face by 180° around the vertical axis (
y-axis
). After doing that, you can then translate this second square face along thez-axis
in order to move it to the back.The translate value is again positive in this case. Just like the translate
transform
moves the coordinate system of the element that is translated, the rotatetransform
... well... rotates it. This means that afterrotateY(180deg)
is applied, the+
of thez-axis
points towards the back (not towards the front anymore).So the CSS that rotates and then translates the second face into its position on the cube is:
Note: the cube is a really simple 3D shape, but one CSS property that I find really useful to check whether I've rotated faces the right way is
backface-visibility
. If I set it tohidden
and I don't see the rotated element, it means that I'm looking at it from the back.1.3.3 Put the third face to the right
First of all, its front has to "look" towards the right. This means that it has to be rotated around the
y-axis
so that the+
of thez-axis
ends up pointing towards the right and then it has to be translated along the positivez-axis
by the same positive value (8em
in this case) that is half the length of the side of the square.Rotated by what angle? Well, 90°, which means the CSS needed is:
1.3.4 Put the fourth face to the left
First rotate it by
90°
, but the other way, to make its front "look" towards the left. "The other way" meansrotateY(-90deg)
, then apply the same oldtranslateZ(8em)
. In one CSS line:1.3.5 Put the fifth face at the top
First rotate it by
90°
around thex-axis
and then translate along thez-axis
(which points up after the rotation). CSS:1.3.6 Put the sixth (and last!) face at the top
Rotate it by
90°
the other way around thex-axis
, then translate it along thez-axis
(which points down after the rotation). CSS:1.4 Perspective and realistic looking 3D shapes
All the faces of the cube are now in place. But this won't look like much of a 3D shape unless the faces that are closer seem bigger than those that are further away. The CSS property that takes care of this is called
perspective
and is applied on the parent of the elements which have 3D transforms applied on them.It still won't look like much of a 3D shape if you look perpendicular to the center of the front face because you won't see any of the other faces. To fix this, you need to rotate the cube itself in 3D. And this is why it's important that the browser allows nesting of 3D transformed elements.
You enable nesting of 3D transformed elements with
transform-style: preserve-3d;
on the parent element (.cube
in this case). Unfortunately, IE10/11 do not support thepreserve-3d
value for thetransform-style
property (only support theflat
value), so you cannot have a realistic looking cube in IE yet (unless you take the 3D transforms applied on the cube and chain them before the transforms applied for each face, which means one set of keyframes for each face if you want to animate the cube as a whole).Update:
transform-style: preserve-3d
now landing in IE as well.Note: If you also apply 3D transforms on the
.cube
, then you should move theperspective
property on the parent of the.cube
.2 Animating the CSS cube
That's done using just the regular keyframe animations for the
.cube
element. Let's say you want to rotate it:You can have multiple keyframes, with rotations around different axes, but this is the basic idea.
TL;DR
Just give me the damn demo! Alright, here it is:
simple rotating cube demo
And a few more demos I've done recently and which show how to create other slightly more complex 3D shapes:
❆ square antiprism
❆ cuboctahedron
❆ rhombicuboctahedron
❆ rhombic dodecahedron
❆ octahedron
❆ truncated cube
Its all css3 and javascript. Just inspect the site in your favorite inspector, dig into the dom, and you'll see something like
how much javascript you need depends on how you want to implement it. It can be 'a lot' or 'a little'.
The more modern a browser, the better the change it will run well. Check here to see which browsers support what.