WebKit on Mac OS X now has support for CSS 3D transforms, which allow you to position elements on the page in three-dimensional space using CSS. This is a natural extension of 2D transforms, which we described in an earlier blog post. 3D transforms have been supported on iPhone since 2.0, and now we’re please to announce that we have currently added support for Leopard and later.
If you want to jump right in and see a demo, make sure you’re running recent WebKit nightly build on Leopard or later, and load this example:
Here’s a screenshot for those not running a recent-enough WebKit (if you are, hover over it for a treat!):
Like many of the examples you’ll see here, this one combines CSS transforms with CSS transitions and animations to great effect.
3D transforms are applied via the same
-webkit-transform property as 2D transforms. For example, here’s how to rotate an element about the Y (vertical) axis:
There are several new transform functions available for use in the
- translate3d(x, y, z), translateZ(z)
- Move the element in x, y and z, and just move the element in z. Positive z is towards the viewer. Unlike x and y, the z value cannot be a percentage.
- scale3d(sx, sy, sz), scaleZ(sz)
- Scale the element in x, y and z. The z scale affects the scaling along the z axis in transformed children.
- rotateX(angle), rotateY(angle), rotate3d(x, y, z, angle),
- The first two forms simply rotate the element about the horizontal and vertical axes. Angle units can be degrees (deg) radians (rad) or gradians (grad). The last form allows you to rotate the element around an arbitrary vector in 3D space; x, y and z should specify the unit vector you wish to rotate around (we’ll normalize it for you).
- This function allows you to put some perspective into the transformation matrix. For an explanation of p, see below. Normally perspective is applied via the
-webkit-perspectiveproperty, but this function allows you to get a perspective effect for a single element, with something like:
-webkit-transform: perspective(500px) rotateY(20deg);
- This function allows you to specify the raw 4×4 homogeneous transformation matrix of 16 values in column-major order. Have fun with that!
We’ve also extended one other CSS transform property, and implemented the four other 3D-related properties described in the spec:
-webkit-transform-origin now accepts three values, allowing you to specify a z offset for the transform origin.
-webkit-perspective is used to give an illusion of depth; it determines how things change size based on their z-offset from the z=0 plane. You can think of it as though you’re looking at the page from a distance p away. Objects on the z=0 plane appear in their normal size. Something at a z offset of p/2 (halfway between the viewer and the z=0 plane) will look twice as big, and something at a z offset of -p will look half as big. Thus, large values give a little foreshortening effect, and small values lots of foreshortening. Values between 500px and 1000px give a reasonable-looking result for most content.
The default origin for the perspective effect is the center of the element’s border box, but you can control this with
Here’s an example that shows how perspective works:
The interesting thing about
-webkit-perspective is that it does not affect the element directly. Instead, it affects the appearance of the 3D transforms on the transformed descendants of that element; you can think of it as adding a transform that gets multiplied into the descendant transforms. This allows those descendants to all share the same perspective as they move around.
We’ve described how you can assign 3D transforms to elements and make them look three-dimensional with some perspective. However, so far, all the effects are really just painting effects. Those transformed children are still rendering into the plane of their parent; in other words, they are flattened.
When you start to build hierarchies of objects with 3D transforms, flattening is not what you want. You want parents and children to live in a shared three-dimensional space, and to all share the same perspective which propagates up from some container. This is where
-webkit-transform-style comes in.
-webkit-transform-style has two values:
flat: This is the default value, and gives the behavior described above; transformed children are flattened into the plane of their parent (think of the 3D transform as simply a painting effect).
preserve-3d: This value states that the element to which it is assigned does not flatten its children into it; instead, those children live in a shared 3D space with the element.
Here’s an example that shows transform-style in action:
A common pattern, therefore, is to have content that looks like this:
<div class="container" style="-webkit-perspective: 600px"> <div class="box" style="-webkit-transform-style: preserve-3d; -webkit-transform: rotateY(10deg)"> <div class="leaf" style="-webkit-transform: rotateX(10deg)"></div> </div> </div>
Here both ‘leaf’ and ‘box’ share the same 3D space, so both appear with the perspective specified on the container. ‘box’ can also be rotated with a transition or animation, and ‘leaf’ will move around as ‘box’ moves, in perspective.
One thing you may have noticed in these demos is that it’s quite common to have a 3D transform that flips an element around so that you can see its reverse side. In some cases you don’t want the element to appear at all in this situation (say, for example, you want to position two elements back-to-back, so you need to hide the one that’s facing away from the viewer). This is the reason for the last 3d-related property,
-webkit-backface-visibility. Its two values—
visible (the default), and
hidden—specify whether the element is visible or not when that element is transformed such that its back face is towards the viewer.
Here’s a final example that shows backface-visibility in action, along with more 3D goodness, animations and transitions:
We hope you have a blast with these new features, and share your creations with us. If you find bugs, please report them at bugs.webkit.org.