Here's something you might not know: the CSS transform
and individual transform properties (translate
, rotate
and scale
) are additive. If you set both, the values are all added together to determine the final transformation.
CSS properties overwrite each other
If you first set a font-size in a font
property and then set a different font-size in a font-size
property, that font-size
overwrites the font
property:
body {
font: 16px system-ui;
font-size: 20px;
}
/* resulting font is system-ui in 20px */
Likewise, if you set a border-top
, and then set a border-color
, the color of your border-top
will be overwritten.
body {
border-top: 5px solid red;
border-color: blue;
}
/* resulting border-top is 5px solid blue */
In CSS the behavior is that properties that affect the same thing will overwrite each other.
But with CSS transform
and the individual transform properties, the values are added together instead, why?
The CSS transform property
The transform
property lets you transform elements in different ways, for example by translating them (moving them around in x/y/z), scaling them, rotating them, skewing them, etc. You can set multiple transformations at once, by separating them with spaces. For example:
transform: translate(10px, 20px) rotate(45deg) scale(2);
This is powerful because the order matters: you can translate
and then rotate
, or rotate
and then translate
, and you'll get different results:
<div class="box1">1</div>
<div class="box2">2</div>
.box1 {
transform:
translate(200px, 0px) rotate(45deg);
}
.box2 {
transform:
rotate(45deg) translate(200px, 0px);
}
This powerful API also means that if you want to change one of the transformations, you have to set all of them again or they get overridden.
If you have a rotated element that you want to scale up on hover, you will also need to rotate that element again in the hover state, or the rotation will be lost. Try hovering over the element below, for example:
<div class="box1">1</div>
.box1 {
transform: rotate(45deg);
}
.box1:hover {
transform: scale(1.5);
}
The element scales in, but you lose the rotation.
Individual transform properties
That's where the individual properties come in: they let you set, and re-set, each transformation separately.
For example, you can set the translate
property to move an element around, and then set the scale
property on hoverto scale it up, without losing the translation:
<div class="box1">1</div>
.box1 {
rotate: 45deg;
}
.box1:hover {
scale: 1.5;
}
Additive transforms
If you set both transform
and individual transform properties on an element, the transforms are additive. This means that all the transform values are added together to determine the final transformation.
In the example below, both elements have a transform
, but the second element also has a translate
. You can edit the CSS below to see how the total translation changes.
<div class="box1">1</div>
<div class="box2">2</div>
.box1, .box2 {
transform: translate(200px, 100px);
}
.box2 {
translate: 200px 0;
}
This specific behavior is described in the CSS transforms specification under paragraph 6: Current Transformation Matrix.
That explainer is for browsers so it's a bit technical. If we omit the non-transform properties, the order of the transformations is as follows:
- Apply the
translate
property - Apply the
rotate
property - Apply the
scale
property - Apply the
transform
functions from left to right
So now you know too: the transform
and individual transform properties are additive. If you set both, the total translation combines everything you've set.
If you want a more in-depth, step-by-step explainer of the CSS transformation matrix, this recent post by Schalk Neethling is a great resource: CSS transforms and the matrix
Video by FrontendFYI
Jeroen Reumkens from FrontendFYI has a great video about this topic and how it relates to changes in Tailwind CSS 4, so if you prefer video check it out:
Don't forget to like the video if it was useful! ;)