Menu Search
Jump to the content X X
Smashing Conf San Francisco

We use ad-blockers as well, you know. We gotta keep those servers running though. Did you know that we publish useful books and run friendly conferences — crafted for pros like yourself? E.g. upcoming SmashingConf San Francisco, dedicated to smart front-end techniques and design patterns.

Adventures In The Third Dimension: CSS 3D Transforms

Back in 2009, the WebKit development team proposed a new extension to CSS that would allow Web page elements to be displayed and transformed on a three-dimensional plane. This proposal was called 3D Transforms, and it was soon implemented in Safari for Mac and iOS. About a year later, support followed for Chrome, and early in 2011, for Android. Outside of WebKit, however, none of the other browser makers seemed to show much enthusiasm for it, so it’s remained a fairly niche and underused feature.

That’s set to change, though, as the Firefox and Internet Explorer teams have decided to join the party by implementing 3D Transforms in pre-release versions of their browsers. So, if all goes according to plan, we’ll see them in IE 10 and a near-future version of Firefox (possibly 10 or 11, but that’s not confirmed yet), both of which are slated for release sometime this year.

Further Reading on SmashingMag: Link

That being the case, this is an ideal time to get ahead of the curve and start learning about the possibilities and potential of adding an extra dimension to your Web pages. This article aims to help you do just that, by taking you on a flying tour of the 3D Transforms syntax.

Please bear in mind that in order to see the examples in this article, you’ll need a browser that supports 3D Transforms; as I write this, that’s Safari, Chrome, IE 10 Platform Preview5 or Firefox Aurora6.

The Third Dimension Link

On the Web, we’re accustomed to working in two dimensions: all elements have width and height, and we move them around the screen horizontally (left to right) and vertically (top to bottom). The move to a third dimension can be thought of as adding depth to elements, and adding movement towards and away from you (the viewer). Think about 3D films in which objects are constantly thrust out of the screen towards you in an attempt to demonstrate the possibilities of the extra depth.

To use 3D Transforms in CSS, you’ll need to know about axes (that’s the plural of axis, not the plural of axe). If you already know about working in three dimensions or remember using axes in math class at school, you can skip the next section. For everyone else, here is…

A Quick Primer On Axes Link

I just mentioned that on the 2-D Web, we move elements around horizontally and vertically. Each of these directions is called an axis: the horizontal line is known as the x-axis, and the vertical line is the y-axis. If we think of the top-left corner of an element as our origin (i.e. the point from which movement is measured), a movement to the left is a negative movement along the x-axis, and a move to the right is a positive movement along the x-axis. The same goes for moving an element up (negative on the y-axis) and down (positive on the y-axis).

The third dimension is known as the z-axis and, as I said, can be thought of as towards or away from you; a negative movement along the z-axis is away from you, and a positive movement is towards you.

Showing the three axes: x (left-right), y (up-down) and z (away-towards).

If you’ve read all of this talk of axes and negative movements and you’re rubbing your eyes and blinking in disbelief and misunderstanding, don’t worry: it will all become clear when you get stuck in the code. Come back and read this again after a few examples and it should all be clear.

Transformation Functions Link

The various transformations are all applied with a single CSS property: transform — yes, the same property that’s used for 2-D CSS Transforms. At the moment, this property is still considered experimental, so remember to use all of the browser prefixes, like so:

div {
  -moz-transform: foo;
  -ms-transform: foo;
  -o-transform: foo;
  -webkit-transform: foo;

Note that Opera doesn’t currently have an implementation of 3D Transforms, but I’m including it here because work is apparently underway. For the sake of clarity, in the examples throughout this article, I’ll use only non-prefixed properties, but remember to include all of the prefixed ones in your own code.

Anyway, the transform property accepts a range of functions as values, each of which applies a different transformation. If you’ve used 2-D CSS Transforms, then you’ll already know many of these functions because they are quite similar (or, in some cases, the same). Here are all of the 3D functions:

  • matrix3d
  • perspective
  • rotateX, rotateY, rotateZ, rotate3d
  • scaleX, scaleY, scaleZ, scale3d
  • translateX, translateY, translateZ, translate3d

Now, matrix3d definitely sounds the coolest, but it’s so unbelievably complex (it takes 16 values!) that there’s no way I could cover it in this article. So, let’s put that aside and take a quick look at the others.

Rotation Link

To explain what this does, I’ll have to ask you to do a little mental exercise (which will come in useful later in the article, too). Imagine a sheet of card with a string running through the middle that fixes it in place. By taking the top corners in your fingers, you can move the card up and down, left and right, and forwards and backwards, pivoting around the string. This is what the rotate() function does. The individual functions rotateX(), rotateY() and rotateZ() take a deg (i.e. degree) value and move the element around its point of origin (where the string passes through it) by that much.

Have a look at our first example7 (a screenshot is shown below in case you don’t have access to a supported browser). Here we’ve rotated each of the elements 45° around a different axis (in order: x, y, z), so you can see the effect of each. The semi-translucent red box shows the original position of the element, and if you mouse over each, you’ll see the transformations removed (I’ve used this convention in all of the examples in this article).

Each element is rotated 45° around a different axis: x (left), y (center) and z (right).

There is a rotate3d() function as well, but it’s too complex to explain in a brief article like this one, so we’ll skip it.

Translation Link

This is really just a fancy way of saying “movement.” The functions translateX(), translateY() and translateZ() each take a length value, which moves the element by that distance along the given axis. So, translateX(2em) would move the element 2 ems to the right, and translateZ(-10px) would move the element 10 pixels away from the viewer. There’s also a shorthand function, translate3d(), which takes three values in order, one for each axis, like so: translate3d(x, y, z).

In our second example9, we’ve translated each of the elements by -20 pixels along a different axis (in order: x, y, z).

Each element is translated by -20 pixels along a different axis: x (left), y (center) and z (right).

Note that translation of an element is similar to relative positioning, in that it doesn’t affect the document’s flow. The translated element will keep its position in the flow and will only appear to have moved, meaning it might cover or show through surrounding elements.

Scaling Link

This just means making bigger or smaller. The three functions scaleX(), scaleY() and scaleZ() each take a unitless number value, which is used as a multiplier. For scaleX() and scaleY(), this is applied directly to the width and height; for example, applying scaleY(1.5) to an element with a height of 100 pixels would transform it to 150 pixels high, and applying scaleX(0.75) to an element with a width of 100 pixels would transform it to 75 pixels wide.

The scaleZ() function behaves slightly differently. Transformed elements don’t actually have any depth to increase or decrease; what we’re doing is more like moving a 2-D object around in 3D space. Instead, the value given to scaleZ() acts as a multiplier for the translateZ() function that I explained in the last section. So, applying both translateZ(10px) and scaleZ(2) would translate an element 20 pixels along the z-axis.

There’s also a shorthand property, scale3d(), which, like translate3d(), takes three values, one for each of the individual functions: scale3d(x,y,z). So, in the following code example, the same transformation applies to both of the elements:

.e1 {
   transform: scaleX(1.5) scaleY(1.5) scaleZ(0.75);

.e2 {
   transform: scale3d(1.5,1.5,0.75);

Perspective Link

The perspective() function is quite simple, but what it actually does is quite complex. The function takes a single value, which is a length unit greater than 0 (zero). Explaining this is a little complicated; the length is like a distance between you and the object that you’re viewing (a tutorial on Eleqtriq11 has a more technical explanation and diagram). For our purposes, you just need to know that the lower the number, the more extreme the 3D effect will appear; any value below 200px, for example, will make the transformation appear very exaggerated, and any value of 1000px or more will seem to have no effect at all.

In our third example12, we have three transformed elements, each with a different value for the perspective() function: 25px, 50px and 200px, respectively. Although the difference between the three is very discernible, it’s even clearer when you mouse over to see the transformations removed.

Each element has a different value for the perspective() function: 25px (left), 50px (center) and 200px (right).

Note that I’ve transformed the parent elements (equally) so that we can see the degree of perspective more clearly; sometimes the difference in perspective values can be imperceptible.

Other Properties Link

In addition to transform, you’ll need to know about a few other important properties.

transform-style Link

If you’ll be applying 3D transformations to the children of an already transformed element, then you’ll need to use this property with the value preserve-3d (the alternative, and default, is flat). This means that the child elements will appear on their own planes; without it, they would appear flat in front of their parent.

Our fourth example14 clearly illustrates the difference; the element on the left has the flat value, and on the right, preserve-3d.

The element on the left has a transform-style value of flat, and the one on the right has a value of preserve-3d.

Something else to note is that if you are transforming child elements, the parent must not have an overflow value of hidden; this would also force the children into appearing on the same plane.

transform-origin Link

As mentioned, when you apply a transformation to an element, the change is applied around a point directly in the horizontal and vertical middle — like the imaginary piece of string we saw in the earlier illustration. Using transform-origin, you can change this to any point in the element. Acceptable values are pairs of lengths, percentages or positional keywords (top, right, etc.). For example:

div {
   transform-origin: right top;

In our fifth example16, you can see the same transformations applied to two elements, each of which has a different transform-origin value.

The element on the left has a transform-origin value of center center, and the one on the right has a value of right top.

The difference is clearly visible, but even more obvious if you pass the mouse over to see the transformation removed.

backface-visibility Link

Depending on which transformation functions you apply, sometimes you will move an element around until its front (or “face”) is angled away from you. When this happens, the default behavior is for the element to be shown in reverse; but if you use backface-visibility with a value of hidden, you’ll see nothing instead, not even a background color.

perspective and perspective-origin Link

We introduced the perspective() function earlier, but the perspective property takes the same values; the difference is that the property applies only to the children of the element that it’s used on, not the element itself.

The perspective-origin property changes the angle from which you view the element that’s being transformed. Like transform-origin, it accepts lengths, percentages or positional keywords, and the default position is the horizontal and vertical middle. The effect of changing the origin will be more pronounced the lower the perspective value is.

Conclusion Link

By necessity, we’ve flown through the intricacies of the 3D transformations syntax, but hopefully I’ve whetted your appetite to try it out yourself. With a certain amount of care for older browser versions, you can implement these properties in your own designs right now. If you don’t believe me, compare the list of “More adventures” on The Feed18 website that I built last year in a browser that supports 3D transforms and in one that doesn’t, and you’ll see what I mean.

Some of the concepts used in 3D transforms can be quite daunting, but experimentation will soon make them clear to you in practice, so get ahold of a browser that supports them and start making some cool stuff. But please, be responsible: not everything on the Web needs to be in three dimensions!

Further Reading and Resources Link


Footnotes Link

  1. 1
  2. 2
  3. 3
  4. 4
  5. 5
  6. 6
  7. 7
  8. 8
  9. 9
  10. 10
  11. 11
  12. 12
  13. 13
  14. 14
  15. 15
  16. 16
  17. 17
  18. 18
  19. 19
  20. 20
  21. 21
  22. 22
  23. 23
  24. 24

↑ Back to top Tweet itShare on Facebook

Peter is a front-end technologist, developer, writer, speaker, and author of The Book of CSS3 and The Modern Web. He blogs at Broken Links and tweets as @stopsatgreen. He lives in London, England.

  1. 1

    Nice CSS 3D tutorial.I love this explanation.

  2. 2

    At work we have been using 3D transforms for the flip effect. What we used it for was compressing forms down by have two parts in the same bit and you just flip the card over and the other half is there.

    We also used to show data and then on the back have some options.

  3. 3

    Please use “px” at the end of the perspective values. If you don’t, this will only works with Webkit (your examples don’t work correctly with Firefox because of that).

  4. 5

    “So, let’s put that aside and take a quick look at the others.”

    “but it’s too complex to explain in a brief article like this one, so we’ll skip it.”

    Can we publish articles like this when they’re a little more comprehensive instead of a high level fly over?

    • 6

      Peter Gasston

      January 6, 2012 7:51 am

      Hi bill, I considered covering each, but believe me they are far more complex than would justify their inclusion here; especially matrix3d(), which would need at least half of the length of this article on its own, and will probably be of little use to anyone who’s not using it for complex 3D modelling with JavaScript.

      rotate3d() is slightly easier to explain but would still need 3 or 4 paragraphs, and most of what it can do is better covered by the three individual functions.

      I honestly feel this article is better off without them, but I’m sorry if you feel like I just brushed over them.

      • 7

        Rizqi Djamaluddin

        January 8, 2012 6:14 am

        I understand the snip-outs – they probably are indeed best jumped over, lest the article descend into maths that whisk away all the designers in the crowd. It may be useful, however, to make it clear that those functions can be replaced with the other, more granular functions, or people might think there’s still functionality left undocumented.

      • 8

        Can you explain matrix3d, no where on internet there is anything about it.

  5. 9

    Douglas Bonneville

    January 6, 2012 11:58 am

    Cool! I hadn’t seen a diagram on how to position my fingers while saying “waaassssuuuuup”. :)


    I’d love to see how to integrate this into a jQuery carousel.

  6. 10

    Vicente Millán

    January 7, 2012 5:12 am

    Great post!

    I think it is just a further step… In my opinion we still are in the childhood of css. Dont’you?

  7. 11

    It’s a really fascinating glimpse into what we’ll be able to call upon for our creative endevours in the future, but really, that’s all this is. It’s great that Chrome is (once again) already ahead of the mark, but I want to use these now, within the briefs and projects that I currently have on my desk, or otherwise in the immediate offing!!

    God knows what will be tantalising us once all the above is a cross-browser/-platform norm. I guess that’s why we do whats we do…..

    • 12

      Peter Gasston

      January 7, 2012 3:54 pm

      You *can* use these now, as long as you plan for what happens in browsers which don’t support these properties yet. Take a look at the example I give in the last paragraph of the article; I did this over a year ago. It works in all browsers, but the behaviour is slightly different depending on their capabilities.

    • 13

      Rizqi Djamaluddin

      January 8, 2012 6:16 am

      Notably, most modern browsers do support old 2D transforms, so you can have relatively usable fallbacks (such as using a scale animation instead of a z-axis rotate page flip). I’m not sure how to make sure the browsers that do support 3D transforms don’t execute these 2D ones, sans using javascript to sniff for browser support.

      Future article? *wink*

  8. 14

    Tanner Godarzi

    January 7, 2012 7:45 pm

    I felt compelled to comment due to my experience with CSS 3D transforms on mobile devices. Using Translate3D(X,Y,Z) for animating a 2D transition (keeping Z at 0) adds allows iOS to use hardware acceleration for rendering the transition. The only downside is version 2.2 of Android has incredibly buggy support for Translate3D. Also, using back face:hidden on a div that contains a form or anything that allows a user to input data will break in Android 2.2

  9. 15

    Awesome tutorial!

  10. 16

    Is it just my Browser (latest Firefox) or do these examples really DO NOT work in firefox? In Safari they run perfectly. Really strange.

    • 17

      Rizqi Djamaluddin

      January 9, 2012 12:28 am

      You need to define what you mean by “latest Firefox”. You need Firefox Aurora, one of the testing stages/experimental builds of Firefox.

  11. 18

    Excellent article, thought it wise not to dive into the depths of granular 3d transforms!

    Question: was thinking about the fallback situation and how best to only serve 3d CSS to webkit – is JS feature support detection the way forward in your opinion?

    • 19

      Peter Gasston

      January 9, 2012 6:05 am

      JS feature support is one way forward, as long as you plan it well, remembering that some people don’t have JS enabled; make sure it all works without JS first, then add the 3D properties only if the user has JS enabled and their browser supports 3D.

      But you may not need JS at all; remember, if a browser doesn’t understand a property it will skip it and fall back to the last property it did understand; so browsers which don’t support 3D will ignore those properties and fall back to whatever you specified before:

      div:hover {
      transform: scale(1.5); /* Ignored if no 2D Transforms support */
      transform: scale3d(1.5,1.5,2); /* Ignored if no 3D Transforms support */

      That’s not a perfect example, but it should do what you need.

  12. 20

    Great article! Thanks for sharing.

    I can definitely see this and 3D technology (monitors and video cards) hitting it off for the near future of web designing. Can you image what is now possible, and soon to be even more possible, for websites/applications with the combination of 3D transformation and 3D viewing. Hopefully browsers continue to further support 3D transforms.

  13. 21

    Oh great yet more cheesy CSS effects, lets be clear this isn’t and never will be Maya or Swift3D even. The web needs 3D but we should have to do it in CSS it just looks plain down right awful.

  14. 22

    Karim Maassen

    January 12, 2012 5:41 am

    Never mind. Got it. :) Forgot to add -webkit-transform-style: preserve-3d;

  15. 23

    Two words

    CSS Sandpaper.

    get it!
    Does it all with support for IE6 up and everyone.

  16. 24

    Suggestion: When linking off to demo pages, I really liked the ‘return to article’ link. It would be nice, though, if you deep-linked the ‘return’ link back to the point in the article from which you left.

  17. 25

    How horks in IE 9?

    • 26

      I was searching just to find this same issue.I am using CSS Sprites, which is a great pofrermance technique, and I’ve got really disappointed with Firefox because of this For those who not understood what is the real issue, try to imagine this situation I have one image with a lot of logos which I just use background-position to place to the right location of my div. But I do not want that all of my divs have the same appearance. For this kind of situation, I want that sometimes the logo can be placed at the left and sometimes at the right HTML CODE HERE I WANT ONE LOGO TO THE LEFT HERE TO THE RIGHTCSS CODE/* default background position to the left */div{background:url(logos.gif) no-repeat;}/* set background position to the right */div.customdiv{background-position-x:right;}/* positioning the logos */div.logo1{background-position-y:-10px;}div.logo2{background-position-y:-50px;}If I use the standard and firefox logic, I cannot use the background-position-y nor the background-position-x. I’d have to make a redundant logic to all position both at the same time background-position:right -50px;background-position:left -50px;ALWAYS Sorry, I hate to say this, but this time MSIE won.

  18. 27

    Great stuff. Checkout which has some nice 3d flipping effects. Use for temporary email addresses too!


↑ Back to top