Kuan
Kuan

Reputation: 11389

Confusion about the order of CSS transform

All:

When I try CSS transform, something about the order of scale and translate confused me:

<svg>
    <rect x="10" y="10" width="20" height="30" style="stroke: #3333cc; fill:none;"/>
    <rect x="0" y="0" width="20" height="30" style="stroke: #000000; fill:none;" transform="scale(2) translate(10, 10)"/>
</svg>


<svg>
    <rect x="10" y="10" width="20" height="30" style="stroke: #3333cc; fill:none;"/>
    <rect x="0" y="0" width="20" height="30" style="stroke: #000000; fill:none;" transform="translate(10, 10) scale(2)"/>
</svg>

These two give different effects. Could anyone give me some explanation about how the CSS transform be processed and rendered?

Thanks

Upvotes: 1

Views: 101

Answers (2)

jbenker
jbenker

Reputation: 236

Every transform function like scale, translate represents a matrix. And matrix concatenation/multiplication is not commutative. So M1 x M2 must not be equal to M2 x M1.

E.g. a scaling matrix (column major order), scale(2, 2):

m11=2.000   m21=0.000   m31=0.000
m12=0.000   m22=2.000   m32=0.000
m13=0.000   m23=0.000   m33=1.000

E.g. a translation matrix, translate(10, 10):

m11=1.000   m21=0.000   m31=10.000
m12=0.000   m22=1.000   m32=10.000
m13=0.000   m23=0.000   m33=1.000

Scale * Translate:

m11=2.000   m21=0.000   m31=20.000
m12=0.000   m22=2.000   m32=20.000
m13=0.000   m23=0.000   m33=1.000

Translate * Scale:

m11=2.000   m21=0.000   m31=10.000
m12=0.000   m22=2.000   m32=10.000
m13=0.000   m23=0.000   m33=1.000

Upvotes: 1

BSMP
BSMP

Reputation: 4797

From W3C

x = "" The x-axis coordinate of the side of the rectangle which has the smaller x-axis coordinate value in the current user coordinate system.

and Mozilla Developer Network:

This attribute indicates an x-axis coordinate in the user coordinate system. The exact effect of this coordinate depend on each element.

The reason they don't look the same is because scaling the element also scaled the user coordinate system.

I've added two more SVG elements so we can see what it looks like with just the first transform applied to it.

<svg>
    <rect x="10" y="10" width="20" height="30" style="stroke: #3333cc; fill:none;"/>
    <rect x="0" y="0" width="20" height="30" style="stroke: #000000; fill:none;" transform="scale(2)"/>
</svg>

<svg>
    <rect x="10" y="10" width="20" height="30" style="stroke: #3333cc; fill:none;"/>
    <rect x="0" y="0" width="20" height="30" style="stroke: #000000; fill:none;" transform="scale(2) translate(10, 10)"/>
</svg>


<svg>
    <rect x="10" y="10" width="20" height="30" style="stroke: #3333cc; fill:none;"/>
    <rect x="0" y="0" width="20" height="30" style="stroke: #000000; fill:none;" transform="translate(10, 10)"/>
</svg>


<svg>
    <rect x="10" y="10" width="20" height="30" style="stroke: #3333cc; fill:none;"/>
    <rect x="0" y="0" width="20" height="30" style="stroke: #000000; fill:none;" transform="translate(10, 10) scale(2)"/>
</svg>

In the first one the scale is applied first. Now both the rect and the user coordinate system is 2x as big as the purple rect. So when it is moved to 10,10 that is not the same location as it is for the purple rect.

In the second, the rect is moved first. It has the same coordinate system as the purple rect so it ends up in the exact same place. It is then scaled so it's upper left hand corner stays in the same place.

Upvotes: 1

Related Questions