css transforms: styling the web in two dimensions

One feature that Firefox 3.5 adds to its CSS implementation is transform functions. These let you manipulate elements in two dimensional space by rotating, skewing, scaling, and translating them to alter their appearance.

I’ve put together a demo that shows how some of these functions work.

There are four animating objects in this demo. Let’s take a look at each of them.

Rotating the Firefox logo

On the left, we see the Firefox logo in a nice box, happily spinning in place. This is done by periodically setting the rotation value of the image object, whose ID is logoimg, like this:

  var logo = document.getElementById("logoimg");
 
  logoAngle = logoAngle + 2;
  if (logoAngle >= 360) {
    logoAngle = logoAngle - 360;
  }
 
  var style = "-moz-transform: rotate(" + logoAngle + "deg)";
  logo.setAttribute("style", style);

Every time the animation function is run, we rotate it by 2° around its origin by constructing a style string of the form -moz-transform: rotate(Ndeg).

By default, all elements’ origins are at their centers (that is, 50% along each axis). The origin can be changed using the -moz-transform-origin attribute.

Skewing text

We have two examples of skewing in this demo; the first skews horizontally, which causes the text to “lean” back and forth along the X axis. The second skews vertically, which causes the baseline to pivot along the Y axis.

In both cases, the code to accomplish this animation is essentially identical, so let’s just look at the code for skewing horizontally:

  text1SkewAngle = text1SkewAngle + text1SkewOffset;
  if (text1SkewAngle > 45) {
    text1SkewAngle = 45;
    text1SkewOffset = -2;
  } else if (text1SkewAngle < -45) {
    text1SkewAngle = -45;
    text1SkewOffset = 2;
  }
 
  text1.style.MozTransform = "skewx(" + text1SkewAngle + "deg)";

This code updates the current amount by which the text is skewed, starting at zero degrees and moving back and forth between -45° and 45° at a rate of 2° each time the animation function is called. Positive values skew the element to the right and negative values to the left.

Then the element’s transform style is updated, setting the transform function to be of the form skewx(Ndeg), then setting the element’s style.MozTransform property to that value.

Scaling elements

The last of the examples included in the demo shows how to scale an element using the scale transform function:

  text3Scale = text3Scale + text3ScaleOffset;
  if (text3Scale > 6) {
    text3Scale = 6;
    text3ScaleOffset = -0.1;
    text3.innerHTML = "It's going away so fast!"
    text3.style.color = "blue";
  } else if (text3Scale < 1) {
    text3Scale = 1;
    text3ScaleOffset = 0.1;
    text3.innerHTML = "It's coming right at us!";
    text3.style.color = "red";
  }
 
  text3.style.MozTransform = "scale(" + text3Scale + ")";

This code scales the element up and down between its original size (a scale factor of 1) and a scale factor of 6, moving by 0.1 units each frame. This is done by building a transform of the form scale(N), then setting the element’s style.MozTransform property to that value.

In addition, just for fun, we’re also changing the text and the color of the text in the block as we switch scaling directions, by setting the value of the block’s innerHTML property to the new contents.

Final notes

Three more tidbits to take away from this:

First, note that as the scaling text grows wider, the document’s width changes to fit it, getting wider as the text grows so that its right edge passes the edge of the document, then narrower as it shrinks again. You can see this by watching the scroll bar at the bottom of the Firefox browser window.

Second, note that you can actually select and copy the text not only while the elements are transformed, but the selection remains intact while the text continues to transform (although when we change the contents of the scaling example, the selection goes away).

Third, I didn’t cover all the possible transforms here. For example, I skipped over the translate transform function, which lets you translate an object horizontally or vertically (basically, shifting its position by an offset). You can get a full list of the supported transforms on the Mozilla Developer Center web site.

Obviously this demo is somewhat frivolous (as demos are prone to be). However, there are genuinely useful things you can do with these when designing interfaces; for example, you can draw text rotated by 90° along the Y axis of a table in order to fit row labels in a narrow but tall space.


9 comments

  1. Anonymous

    As far as I can tell, these transforms don’t actually put any content past the right edge of the screen, so why do they produce a widened document and corresponding horizontal scrollbar?

    July 13th, 2009 at 12:15

  2. Jim B

    Wow, that text looks terrible. Ideally the text would look rigid during translation/rotation/scaling, but the character spacing hops all over the place. It seems like there is some quantization going on that is independent of the eventual display resolution/orientation.

    Perhaps font hinting is done assuming some default size/offset/rotation, then the transformation is applied, resulting in the ratcheting.

    July 13th, 2009 at 12:40

  3. Ken Arnold

    Was just playing with this a bit, trying to find a productive use for the skew transform. Well I don’t know if this counts, but: open up Firebug, and inspect one of the .wp_syntax elements. Add `-moz-transform: skewx(-3deg)` to the .wp_syntax style (right pane), and `-moz-transform: skewx(3deg)` to `.wp_syntax pre`’s styles (two elements down).

    Combined with a little -moz-border-radius, it might be a nice effect for making text stand out. Or it might just make you feel like your monitor is tilted. Your call.

    July 13th, 2009 at 15:48

  4. Ken Arnold

    Still playing with this page using Firebug… If you rotate an element like the `div.code` or `pre` elements in this article, the height of the enclosing element (the `div.wp_syntax` with scrollbars) doesn’t change, and the rotated text gets cut off. Can anyone explain why that happens and how to get the bounding box to superscribe the transformed element?

    July 14th, 2009 at 08:09

  5. nemo

    http://m8y.org/tmp/www.bitstampede.com/demos/css-transforms/

    This is a fix of his demo to support Webkit.

    July 15th, 2009 at 06:01

  6. nemo

    Oh. And the scrollbar doesn’t have that odd behaviour in Safari.

    July 15th, 2009 at 08:31

  7. Eric Shepherd

    Sorry about that with the webkit compatibility; I’ll fix the demo tomorrow when I have a few minutes to update it. Just slipped through the cracks.

    July 16th, 2009 at 14:55

  8. Eric Shepherd

    I’ve updated the sample on my web site to work in WebKit based browsers. The differences are pretty minor; instead of

    text1.style.MozTransform = “skewx(” + text1SkewAngle + “deg)”;

    I just do

    text1.style.MozTransform = “skewx(” + text1SkewAngle + “deg)”;
    text1.style.WebkitTransform = “skewx(” + text1SkewAngle + “deg)”;

    July 17th, 2009 at 11:51

  9. Sjoerd Visscher

    The transformed text looks way better in Chrome than in Firefox. Chrome doesn’t have the issues Jim B talks about.

    July 22nd, 2009 at 04:23

Comments are closed for this article.