The Wayback Machine - https://web.archive.org/web/20150907174913/http://staff.washington.edu/fmf/2009/03/25/iphone-3d-css-transformations/
  • CSS, Web Apps 25.03.2009

    The current version of Mobile Safari on the iPhone and iPod touch allow you to do 3D transformations in CSS. This allows you to give objects perspective and rotation in 3D space, as well as the ability to use transitions and animations.

    This example shows how to apply perspective, as well as applying rotation with a transition, similar to how a Dashboard widget flips to the settings screen:

    Side A
    Side B

    Tap to flip

    If you’re trying to view this page in a browser which does not support the 3D transformations you will see a red box that says “Side B”. If you are running the latest Webkit nightly build, the text will be backwards and clicking on the “Tap to flip” link will cause it to spin to the correct side. With some of the Webkit builds, the transition will appear as if the box were below you when it spins (shaped like a parallelogram), while on other versions you’ll see no distortion (it will narrow down to a vertical line and expand again). Mobile Safari it looks as if you are directly in front of the box (shaped like a trapezoid):

    spinner-iphone

    iPhone

    spinner-webkit

    Webkit

    The HTML for the spinning box and control link is pretty straightforward:

    <div id="spinwrap">
    <div class="sidea">Side A</div>
    <div class="sideb">Side B</div>
    </div>
    <p><a href="#" onclick="return toggleSpinwrap ()">Tap to flip</a></p>

    The toggleSpinwrap() function toggles the class of the spinwrap block between empty and flip. Both the green (“Side A”) and red (“Side B”) boxes have a transition duration of 1.25 seconds and backface visibility set to hidden, which means that if the object is rotated more than 180 degrees (so you are viewing the back of the object) it is no longer visible:

    -webkit-transition-duration: 1.25s;
    -webkit-backface-visibility: hidden;

    To make the effect work, the green box starts out with a rotation of 0 and goes to 180 when the flip class is set, while the green box starts at 180 and goes to 360:

    div#spinwrap div.sidea {
    	background: green;
    }
    div#spinwrap.flip div.sidea {
    	-webkit-transform: rotateY(180deg);
    }
    div#spinwrap div.sideb {
    	background: red;
    	-webkit-transform: rotateY(180deg);
    }
    div#spinwrap.flip div.sideb {
    	-webkit-transform: rotateY(360deg);
    }

    Using rotateX instead of rotateY would cause the boxes to flip on the horizontal axis instead of the vertical axis. In either case, since the red box starts out being rotated 180 degrees, only its back side is facing us which causes it to not be visible. As the two boxes rotate, once the green one goes past 90 degrees we start to see its back and it becomes hidden. Likewise, once the red box passes 270 degrees, its front side becomes visible. Because the two boxes are exactly the same size, they appear as two sides of the same object.

    There’s one more piece to making the effect work the way it does, and that’s setting the perspective. You can set the perspective in the transform itself, such as:

    -webkit-transform: perspective(1000) rotateY(180deg)

    but in this example I chose to set the perspective on the container itself:

    div#spinwrap {
    	-webkit-perspective: 1000;
    }

    Setting the perspective this way makes all child objects inherit the perspective, but the container object itself does not. The advantage is you don’t need to add the perspective to each transform, which not only makes the CSS cleaner but should also help performance.

    The value used for perspective at first seems pretty arbitrary, but once you get used to the scale it becomes easier to grasp. Using smaller values causes the perspective to be more pronounced, since you are closer to the object. This is similar to using a wide-angle lens on a camera; to fill the frame, you need to be closer to the object, which causes more distortion.

    Posted by fmf @ 2:39pm

  • 6 Responses

    • Thanks for the script, worked great however ran into a small problem and was wondering if you had any input.

      Seems that Webkit on the iPhone treats CSS transformations differently then the Safari on the desktop. The transition works in the desktop browser, but floats above the rest on the device. Any ideas?

      div#spinwrap {
      position: relative;
      width: 300px;
      height: 300px;
      margin: 2em auto;
      -webkit-perspective: 1000;
      }
      div#spinwrap div {
      color: black;
      position: absolute;
      width: 100%;
      height: 180px;
      -webkit-transition-duration: 1.25s;
      -webkit-backface-visibility: hidden;
      font-size: 2em;
      text-align: center;
      }
      div#spinwrap div.sidea {
      background: green;
      }
      div#spinwrap.flip div.sidea {
      -webkit-transform: rotateY(180deg);
      }
      div#spinwrap div.sideb {
      background: red;
      -webkit-transform: rotateY(180deg);
      }
      div#spinwrap.flip div.sideb {
      -webkit-transform: rotateY(360deg);
      }

      function toggleSpinwrap () {
      var spinwrap = document.getElementById (‘spinwrap’);
      spinwrap.className = spinwrap.className ? ” : ‘flip’;
      return false;
      }

      Side A

      Tap to flip

    • It probably depends on how your document is set up. The actual transition itself should have no effect on the layout.

      I took the code from this post and put it into a test page and added just before the :

      test paragraph

      The grey box was behind the flipper box both on the desktop and on the iPhone, both for OS 3.0 and 3.1.x

      Hard to tell without a URL to directly check, but hope that helps point you in the right direction.

    • @specialk – What browser/version/platform are you using? I’m checking against the latest Safari/Mac and Mobile Safari on iPhone OS 3.0 and later.

      @Alex – Sorry, my code got deleted. I’ll try again with entities:

      <p style=”background: grey; position: relative; top: 300px”>test paragraph</p>

    • Hey man, thanks so much for this! Really useful stuff!

      Do you have any idea how I could pop Images on both the green and the red side and when I tap the “flip” button it flips from displying one image to displaying another? I’ve been playing around with this all day but haven’t managed to get a useful result.

      Thanks anyway, really a great snippet – and if you could help me out further, well, that would be just perfect:)

      Cheers
      Jonas

      • Not sure what you mean by “pop”, but you should be able to put any content you want on each side. Once you’ve done that, you can use transforms or jQuery to animate the image (presumably you want them to appear they’re moving out of the square).

        In other words, you can treat each side like a normal, static block, and the animation is just a fancy way to show or hide the block.

    Leave a Reply