Why Does Order of Transforms Matter? Rotate/Scale Doesn't Give the Same Result as Scale/Rotate

Why does order of transforms matter? rotate/scale doesn't give the same result as scale/rotate

To illustrate how it works let's consider an animation to show how the scaling effect change the rotation.

.red {  width:80px;  height:20px;  background:red;  margin:80px;  transform-origin:left center;  animation: rotate 2s linear infinite;}@keyframes rotate {  from{transform:rotate(0)}  to{transform:rotate(360deg)}
}
<div class="container"><div class="red"></div></div>

Applying css scale afer rotate

Simply swipe the order of the values in the transform property:

transform: scaleX(2) rotate(45deg)

transform gets executed from right to left. See: How to apply multiple transforms in CSS?

You can also use @keyframes to achieve this effect. See: https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes

svg path transform origin issue

Looks like you just need to swap the order of the translateX and rotate parameters. Matrix multiplication is not commutative.

a {
display: inline-block;
}
svg, path {
transition: all ease .3s;
transform-origin: 50% 50%;
transform-box: fill-box;
}
.circle {
transform: translateX(20px) rotate(-45deg);
opacity: 0;
}
a:hover .circle{
transform: translateX(-20px) rotate(45deg);
opacity: 1;
}
<a href="" class="play">
<svg width="252" height="188" viewBox="0 0 252 188" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M118.765 118.031a2.945 2.945 0 01-2.942-2.942V72.912a2.944 2.944 0 014.827-2.261l25.306 21.089a2.943 2.943 0 010 4.52L120.65 117.35a2.945 2.945 0 01-1.885.682zm2.944-38.837v29.612L139.476 94l-17.767-14.806z" fill="#000"/>
<path class="circle" d="M125.913 144a49.728 49.728 0 01-24.437-6.386 2.942 2.942 0 112.887-5.128c17.169 9.664 38.901 6.676 52.847-7.276 17.21-17.209 17.21-45.21 0-62.419-17.209-17.212-45.212-17.21-62.42 0-17.21 17.21-17.21 45.21 0 62.419a2.944 2.944 0 01-4.162 4.163c-19.503-19.505-19.503-51.24 0-70.744 19.505-19.503 51.238-19.504 70.745 0 19.504 19.505 19.504 51.239 0 70.744-9.608 9.608-22.476 14.627-35.46 14.627z" fill="#FDB500"/></svg>
</a>

Same value of transformations but different order. Why the rotation degree is different?

The order matters to a very great extent for CSS transforms. Please have a look at the four points specified in the Interpolation of Transforms section in the W3C Transform Specs (especially Point 4) and after that have a look at the Interpolation of Matrices section.

Below is an excerpt from the Interpolation of Transforms section without examples (emphasis mine):

When animating or transitioning transforms, the transform function lists must be interpolated. For interpolation between one transform from-transform and a second transforms to-transform, the rules described below are applied.

If both the from- and to-transform are none:

  • There is no interpolation necessary. The computed value stays none.

If one of the from- or to-transforms is none.

  • The value none is replaced by an equivalent identity transform function list for the corresponding transform function list. Both transform function lists get interpolated following the next rule.

If from- and to-transform have the same number of transform functions, each transform function pair has either the same name, or is a derivative of the same primitive.

  • Interpolate each transform function pair as described in Interpolation of transform functions. The computed value is the resulting transform function list.

In all other cases:

  • The transform functions of each transform function list on the from- and to-transform get post multiplied and converted into 4x4 matrices. Each of the matrices gets interpolated following the instructions in Interpolation of matrices. The computed value is the transform function matrix if both initial matrices can be represented by a correlating 3x2 matrix and matrix3d otherwise.


Case 1: Order is different

Based on Interpolation of Transforms section, our test element satisfies point 4 because neither start or end transform value is none and they are not in same order or is a derivative of the same primitive (that is, basically, they are different types of transforms).

So, the transforms specified for the default and :hover states are converted into a matrix and is then interpolated using Interpolation of matrices.

The element's default transform was a rotate(0) scale(0.5) which in matrix form is matrix(0.5, 0, 0, 0.5, 0, 0) and the modified transform is scale(1) rotate(360deg) which is matrix(1, 0, 0, 1, 0, 0). As you can note from the example provided under Interpolation of Matrices section, the information about the one turn gets lost because 360deg is nothing but 0deg in matrix representation. Thus the element only grows and doesn't rotate.



Case 2: Order is same

This is pretty straightforward. As you'd have guessed, it satisfies point 3 in Interpolation of Transforms and is hence not converted into a matrix. It is directly interpolated. So the rotate transform's value is constantly incremented from 0 to 360 inline with the duration of the transition and its timing function. So we get to see the actual rotation also in addition to the grow effect.

Understanding translate after scale in CSS transforms

Since the translation is done after the scale() it will also get scaled so your 320px need to be divided by 0.9 to get the correct value:

320/0.9 = 355.56

In other words, you need to move by 355.56px to actually get the 320px. It's a bit tricky but imagine your self inside another world scaled by 0.9. The perception of the distances outside that world will not be the same inside the scaled world.

A related question to get more details about the math: Why does order of transforms matter? rotate/scale doesn't give the same result as scale/rotate

In your case:

scale(0.9) translate(A, B)

Is equivalent to:

|0.9 0 0|   |1 0 A|   |0.9 0  A*0.9|
|0 0.9 0| x |0 1 B| = |0 0.9 B*0.9|
|0 0 1| |0 0 1| |0 0 1 |

So

Xf =  0.9*(Xi + A);
Yf = 0.9*(Yi + B);

If you do the opposite (translate then scale) you can use 320px

* {
padding: 0;
margin: 0;
}

.container {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
width: 6400px;
height: 3600px;
background-color: red;
transform-origin: 50% 50%;
transform: translate(-320px, -180px) scale(0.9) ;
}
<div class="container">

</div>

CSS - Independent Translate and Scale functions?

According to CSS documentation here:

The translate, rotate, and scale properties allow authors to specify simple transforms independently, in a way that maps to typical user interface usage, rather than having to remember the order in transform that keeps the actions of translate(), rotate() and scale() independent and acting in screen coordinates.

So when you use transform and applies several transform functions (such as translate, scale or rotate), the functions order will effect the visual (which is hard to remember how each function effects the others).

When you use individual transforms you don't have to deal with it and the order doesn't matters.

when an html element is translated then rotated it moves diagonally

It happens because the transforms take place in the order you write them.

It also provides better transform management because you might want to either

  • translate 200px to bottom and then rotate (in place, so you'll know the element does not go sideways):

    transform: translateY(200px) rotate(-15deg);
  • rotate and then translate 200px in the direction of the rotation:

    transform: rotate(-15deg) translateY(200px);

You can also imagine rotate rotating the XoY axis.

The translation written ahead of rotate (actually any previous operations) will take place within the normal axis setup.

The translation written after the rotate will take place within the rotated axis setup.

CGAffineTransform operations inconsistency in order applied

The problem is that you have misinterpreted the first diagram:

enter image description here

You say:

Green v2 translates 100 to the right and then is scaled by .1, where blue v3 is scaled by .1 and then translated 100 to the right

No. Your words are backwards from what the diagram actually shows.

Remember, a transform takes place around a view’s center. Ok, so why is the green view only a tiny bit to the right of its original center?

It’s because first we scaled down to the center and then we moved 10 points right — 10 points because the meaning of a point has first been scaled down to 1/10 of a normal point.

But the blue view is a full 100 points right of its original center, because it translated that 100 points before scaling down.

behavior of flipped coordinate system for text transform and translate

The answer is easier than what you expect. In the second case you are overriding1 the translate with the scale that's why it's not working:

enter image description here

If you want 2 transformation into the same element, you need to put them in the same transform: