A Trick: Individual CSS Transform Functions

We get a lot of power through the single transform property in CSS - allowing us to rotate, translate, scale, and more all at once. But allowing all of those different transform functions into one property can trip us up.

It's common to want to apply different transforms to different states of our elements. Say we have a button that we always want to be translated -150% vertically. When a user hovers over the button we scale the button down a bit, and on press (the active state) we rotate it 180 degrees. This example shows how one might first think to write the CSS for "My Button" as just described, and then the "Expected" button shows a way to get it as intended.

See the Pen Basics with Transform Functions by Dan Wilson (@danwilson) on CodePen.

With the initial styles on the button we are not just adding the scale on hover... we are overriding the original translate as well, so it scales and transitions back to translateY(0).

Why is this? Linear Algebra. The way these transformations happen depend on each other and their order (such that translate(-50%, -50%) scale(.4) rotate(50deg) is different than rotate(50deg) translate(-50%, -50%) scale(.4)), and they boil down to matrix multiplication. But we usually don't need to know transforms at that level. Web developers just want to know how they can maintain these transform functions at an individual level.

See the Pen Order of Transform Functions by Dan Wilson (@danwilson) on CodePen.

Chrome has begun implementing individual properties, such that translate, rotate, and scale become first class properties as seen in this previous example (as of this writing requires Chrome Canary). But this has limitations of its own:

  1. The x, y, and z pieces of each are still tied to a single property currently.
  2. The order will always be translate scale rotate when it is converted to matrices.
  3. Early days - just in Chrome Canary.

So what can we do? 

Use CSS Variables.

Listening to David Khourshid talk about CSS Variables quickly opened my eyes to a lot of opportunities for animating with them. It wasn't until I started putting variables everywhere that their power became even clearer. Without further ado... here is the trick to give us more flexibility (with the how/what/why after the example).

See the Pen CSS Variables + Transform = Individual Properties by Dan Wilson (@danwilson) on CodePen.

We set up a key initial transform for our element with all the variables we intend to change. By modifying the variable value on the different states we can get a CSS rule that looks closer to our original code but with much more flexibility as the complexity grows. In this example we are dealing with many more states than the original example's three by introducing JavaScript (but this is not required: Here is a CSS only version of our original button example). Still, it effectively is one CSS property defined, and we change only one transform function at a time (whether that be in JS or CSS).

Without the CSS variables we would have to do some calculations on the current transition when changing one of the transform functions (which may not be trivial). Then we could know where the other two functions are currently to make sure the transition remained smooth. Every time a variable is changed, a new transition occurs in the same way as if you had rewritten the transform property from scratch, so you still can't have different transitions for each transform function.

How does this compare to the upcoming individual properties in Chrome Canary? 

  1. We can do any combination of x, y, and z since we choose how to set up our initial transform.
  2. Similarly, we can even do whatever order of the transform functions we want (though we lose the (likely) less common use case of changing the order around between states).
  3. I've seen this work well in latest Chrome (56), Firefox (50), and Safari (10.1 on Mac, iOS 10.3) (version 10 supported variables but did not do a smooth transition). Additionally, the latest Windows 10 (Creators Update) releases April 11, 2017, and its new version of Edge supports CSS Variables, so we will soon see how this works there.

Please reach out if you have some creative uses for this technique.