Transforms
Prerequisites: Positioning
Transforms move, rotate, scale, and skew an element visually, without affecting layout — the space it occupies stays the same, and neighbors don't move.
.lift:hover { transform: translateY(-4px); }
.tilt { transform: rotate(-3deg); }
.grow:hover { transform: scale(1.05); }
.flip { transform: scaleX(-1); }
.combo { transform: translateX(20px) rotate(10deg) scale(0.9); }
| Function | Effect |
|---|---|
translate(x, y) / translateX() / translateY() |
Move |
rotate(angle) |
Rotate clockwise (45deg, 0.25turn) |
scale(x, y) |
Resize (1 = original) |
skew(x, y) |
Slant |
Functions apply right to left, relative to the element's own
coordinate system, so order matters: rotate(45deg) translateX(100px)
moves along the rotated axis.
Individual transform properties
translate, rotate, and scale also exist as separate properties,
so you can change one without repeating the others:
.icon { rotate: 0deg; transition: rotate 200ms; }
.open .icon { rotate: 180deg; }
.card:hover { translate: 0 -4px; scale: 1.02; }
They're applied in a fixed order — translate, then rotate, then scale —
and combine with transform.
transform-origin
.door { transform-origin: left center; }
.door.open { transform: perspective(800px) rotateY(-70deg); }
The origin is the pivot point (the center by default).
Layout is unchanged
<style>
.a, .b { width: 100px; height: 50px; }
.a { transform: translateX(200px) scale(2); }
</style>
<div class="a"></div>
<div class="b"></div>
<script>
const a = document.querySelector(".a");
const b = document.querySelector(".b").getBoundingClientRect();
const r = a.getBoundingClientRect();
console.log("a offset size:", a.offsetWidth, "x", a.offsetHeight);
console.log("a painted box:", r.width, "x", r.height, "at x =", r.left);
console.log("b top:", b.top);
</script>
a offset size: 100 x 50
a painted box: 200 x 100 at x = 158
b top: 58
offsetWidth (layout) is still 100px; the painted box
(getBoundingClientRect) is 200px wide and moved. .b starts right
below where .a would be (8px body margin + 50px).
Why transforms are fast
transform and opacity changes can be handled by the compositor,
often on the GPU, without layout or repaint. They're the properties to
animate. Animating left, top, width, or margin forces layout on
every frame and can stutter.
Remember: an inline element can't be transformed — give it
display: inline-block first.