CSS Individual Transform Properties

CSS Transforms appeared on the Web along with CSS Animations and CSS Transitions to add visual effects and motion on the Web. Those technologies have been a staple of the Web platform and Web developers’ toolkit for well over a decade. In fact, the CSS transform property first shipped in Safari all the way back in July 2008 when iPhone OS 2.0 shipped. You can find some historical posts about initial support in WebKit from October 2007, and another post from July 2009 focusing on 3D transforms when CSS Transforms shipped in Mac OS X Leopard.

And now, there is some news in the world of CSS Transforms: individual transform properties are enabled by default in Safari Technology Preview 117. This means that, as in Firefox and Chrome Canary, you can now use the new translate, rotate and scale CSS properties to specify what have so far been functions of the transform property, including 3D operations.

Using these properties is simple and should make Web developers feel right at home. Consider these two equivalent examples:

div.transform-property {
    transform: translate(100px, 100px) rotate(180deg) scale(2);
}

div.individual-properties {
    translate: 100px 100px;
    rotate: 180deg;
    scale: 2;
}

But why would you use these new properties over the transform property? One reason is convenience, as you might deem it simpler to write scale: 2 rather than transform: scale(2) when all you intend to do is scale an element.

But I think the main draw here is that you are now free to compose those various transform properties any way you see fit. For instance, you can easily write a CSS class to flip an element using the scale property without worrying that you might override other transform-related properties:

.flipped {
    scale: -1;
}

Your flipped class will work just fine even if a rotate or transform property applies a rotation to the element.

This feature also comes in handy when animating transforms. Let’s say you’re writing an animation that scales an element up over its entire duration but also applies a rotation for the second half of that animation. With the transform, property you would have had to pre-compute what the intermediate values for the scale should have been when the rotation would start and end:

@keyframes scale-and-rotate {
    0%   { transform: scale(1) }
    50%  { transform: scale(1.5) rotate(0deg) }
    100% { transform: scale(2) rotate(180deg) }
}

While this may not look like such a big deal when you look at it, making any further changes to those keyframes would require recomputing those values. Now, consider this same animation written with the individual transform properties:

@keyframes scale-and-rotate {
    0%   { scale: 0 }
    50%  { rotate: 0deg } 
    100% { scale: 1; rotate: 180deg; }
} 

You can easily change the keyframes and add other properties as you like, leaving the browser to work out how to correctly apply those individual transform properties.

But that’s not all; there is also the case where you want separate animations to apply to an element at the same time. You could split out this single set of keyframes into two different sets and tweak the timing instead:

.animated {
    /* Apply the scale keyframes for 1s and the rotate
       keyframes for 500ms with a 500ms delay. */
    animation: scale 1s, rotate 500ms 500ms;
}

@keyframes scale {
    from { scale: 0 }
    to   { scale: 1 }
}

@keyframes rotate {
    from { rotate: 0deg }
    to   { rotate: 180deg }
}

Now keyframes applying to transforms are not only easier to author, but you can better separate the timing and the keyframes by composing multiple transform animations. And if you are a seasoned CSS Animations developer, you’ll know how important this can be when you factor in timing functions.

Additionally, animating the new individual transform properties retains the same great performance as animating the transform property since these properties support hardware acceleration.

But what about the transform property? How does it relate to those new individual transform properties?

First, remember that the transform property supports transform functions that are not represented as individual transform properties. There are no equivalent CSS properties for the skew(), skewX() and skewY() functions and no property equivalent to the matrix() function.

But what happens when you specify some of the individual transform properties as well as the transform property? The CSS Transform Level 2 specification explains how individual transform properties and the transform-origin and transform properties are composed to form the current transformation matrix. To summarize, first the individual transform properties are applied – translate, rotate, and then scale – and then the functions in the transform property are applied.

This means that there’s a clear model to use those individual transform properties and the transform property together to enhance your ability to transform content on the Web platform.

And before you start using these new properties, it is important that you know how to detect their availability and use transform as a fallback. Here, the @supports rule will allow you to do what you need:

@supports (translate: 0) {
    /* Individual transform properties are supported */
    div {
        translate: 100px 100px;
    }
}

@supports not (translate: 0) {
    /* Individual transform properties are NOT supported */
    div {
        transform: translate(100px, 100px);
    }
}

We encourage you to start exploring how to use those three new properties in Safari Technology Preview in your projects and file bug reports on bugs.webkit.org should you encounter unexpected issues. You can also send a tweet to @webkit or @jonathandavis to share your thoughts on individual transform properties.