Surfin' Safari

3D Transforms

Posted by Simon Fraser on Thursday, July 16th, 2009 at 12:02 pm

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:

Poster Circle

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:

-webkit-transform: rotateY(45deg);

There are several new transform functions available for use in the -webkit-transform property:

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).
perspective(p)
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-perspective property, but this function allows you to get a perspective effect for a single element, with something like:

-webkit-transform: perspective(500px) rotateY(20deg);
matrix3d(…)
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 -webkit-perspective-origin.

Here’s an example that shows how perspective works:

Perspective

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:

Transform Style

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:

Morphing Power Cubes

Mighty Cubes

For more information, see the CSS working drafts on 2D transforms, 3D transforms, transitions and animations. There is also documentation in the Safari Reference Library.

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.

18 Responses to “3D Transforms”

  1. devongovett Says:

    That is just incredible. How long until this makes it into Safari, and all of the other browsers that are based on webkit?

  2. doekman Says:

    Übercool! Who is turning the morphing power cubes into a digital clock?

  3. jackinloadup Says:

    I just want to thank the whole webkit team for giving web users a higher quality of [web] life.

    From me to you.
    Thank you.

    Lucas

  4. CyberSkull Says:

    This is really great stuff! I can’t wait to figure out a practical application to put this in!

  5. cying Says:

    Congratulations, WebKit team!

    To see one application of 3D CSS Transforms, please take a look at the Snow Stack demo.

  6. keishi Says:

    Playing with 3D transforms is so much fun. Here is my try
    http://keishi.net/ThousandSongs/

  7. Brad Says:

    That is truly remarkable. Good demos, too!

  8. Robert Gaal Says:

    This is great. I’ve been waiting for this to come to Webkit desktop for a month, awesome.

    However: after animating something in 3D, how do I give an object thickness or depth? All the squares animated in the examples have a thickness of 0px. I want my sides of an object to have depth as well. How do I do this?

  9. thajeztah Says:

    Very impressive. Can’t wait for the other browsers to catch up :)

  10. Antoine Quint Says:

    @RobertGaal: Elements are transformed in 3D space but are not 3D objects as such. They’re still 2D planes basically, only living in a 3D space, so no depth.

  11. Hywan Says:

    Hey :-) ,

    Very nice job guys. I have made a video, which is available at: http://www.dailymotion.com/video/x9w30t_webkit-css3-transforms-animations-a_tech

  12. raju Says:

    Excellent, breathtaking! I wonder what Webkit will do with JavaScript and CSS in 2 years from now! That’s a true web revolution!

  13. raju Says:

    I’ve done a small proof-of-concept for the OpenLaszlo DHTML runtime, here’s the video in my blog:
    http://openfuture.rajubitter.com/2009/07/17/webkit-css-based-3d-transforms-applied-to-openlaszlo-dhtml/

    As an OpenLaszlo committer I would love to use the technology to help companies move away from Flash based RIAs to open standards like JS/CSS. Having a Flash/SWF runtime as a backup means, that you can deliver that to old browsers like IE/IE8 and older versions of Webkit/Safari and FF.

    Kudos to the Webkit team for what you guys achieve with this great browser!

  14. Paul Hayes Says:

    Excellent stuff, been waiting for this :)

    I’ve created a quick cube interface that can be navigated using arrow keys:
    http://www.fofronline.com/2009-07/animated-css3-cube-interface-using-3d-transforms/

  15. asmeurer Says:

    This has been available on Safari on the iPhone/iPod touch for some time now (load this page in the current iPhone Safari browser). Glad to see that it is finally making its way to the desktop version. Once again, Webkit leaves Firefox in the dust!

  16. dflorey Says:

    Are there any plans to bring this great feature to windows? I’ve no clue if this is feasable as Cairo may not support 3D…

  17. James W Cready Says:

    I’ll apologize up front since this comment has nothing to do with 3D transformations — I’m sorry.

    First question: Why when I “Check for WebKit Updates…” does it sometimes only have to download ~3.0MB but other times it has to download ~30.0MB?

    Second (and more exigent) question: Once the update (even the small ~3.0MB one) has been fully downloaded — which on my connection takes maybe 5 seconds. It take ~25 seconds to “extract” the update; another ~8 seconds to “install” the update. And even after the “install” progress bar has reached 100%, I still see the striped “busy” progress bar for another 3-5 second before I can actually click “Install and relaunch…”

    I’m on a Mac Pro with 2 Dual-Core Xeons at 2.66GHz with 3GB RAM running 10.5.7. I guess my real question is why does it take ~40 seconds to extract and install a ~3.0MB update — it doesn’t seem right to me, or maybe I’m just naïve and those numbers are typical?

  18. esquevin Says:

    I quickly made up this demo. It’s not as fancy as the others, but kinda fun =)
    http://esquevin.com/starwars.html
    I was amazed at how quick and easy it was. Really good job here.