Lesson 30 of 32
Transforms
translate(), scale(), rotate() and skew(), combining multiple functions in one declaration, transform-origin, and why transform/opacity are best for smooth animation.
transform moves, resizes, rotates or skews an element without changing the
normal document flow around it — the element visually shifts, but the space
it was originally occupying doesn't reflow to match. That distinction turns
out to matter for performance, which this lesson ends on.
The four 2D transform functions
.moved { transform: translateX(20px); }
.grown { transform: scale(1.2); }
.spun { transform: rotate(15deg); }
.slanted { transform: skewX(10deg); }translate()— shifts the element.translateX()andtranslateY()move along a single axis;translate(x, y)does both at once. Positivexmoves right, positiveymoves down.scale()— resizes the element.scale(1.2)grows it to 120% in both dimensions;scale(1, 0.5)scales width and height independently.scaleX()/scaleY()do one axis alone. Values below 1 shrink the element.rotate()— spins the element around a fixed point, by angle (deg). Positive values rotate clockwise.skew()— slants the element along an axis, distorting its shape rather than rotating it rigidly.skewX()/skewY()skew one axis;skew(x, y)does both.
None of these change the element's width, height, or position in the
normal document flow as far as its neighbors are concerned — a transformed
element still occupies its original space in the layout, it just visually
renders shifted, scaled or rotated on top of that space. Neighboring elements
don't reflow around a transformed element the way they would if you'd
actually changed its width or margin.
Combining multiple functions
Multiple transform functions can be listed in a single declaration, separated by spaces, and they apply in the order written:
.card {
transform: translateX(10px) rotate(5deg);
}Order matters. translateX(10px) rotate(5deg) moves the element first, then
rotates it around its own (now-shifted) center. rotate(5deg) translateX(10px) rotates first, which changes what direction "X" even points
in for the subsequent translate, since the element's local coordinate system
rotated with it — producing a visibly different result from the first
example. If a combined transform looks wrong, try reversing the order of the
functions before anything else.
transform-origin
By default, rotate() and scale() both pivot around the element's own
center. transform-origin moves that pivot point:
.corner-rotate {
transform-origin: top left;
transform: rotate(15deg);
}With the default center origin, rotating an element spins it in place, its
center staying put. With transform-origin: top left, that same rotation
instead pivots around the element's top-left corner, swinging the rest of
the element around that fixed point — the difference between a clock hand
sweeping around its center pin and a door swinging on a hinge at one edge.
The same idea applies to scale(): an origin at top left grows the element
outward from that corner rather than outward from the middle in every
direction.
transform-origin accepts keywords (center, top, bottom left, etc.) or
explicit lengths/percentages measured from the element's own top-left corner.
Why transform and opacity are the properties to animate
This is a genuine, well-established performance distinction, not a stylistic preference. Changing most CSS properties forces the browser to redo work further up its rendering pipeline:
- Changing
width,height,top,left, ormargincan trigger layout (recalculating the position and size of the changed element and potentially everything around it) followed by paint (redrawing actual pixels) — the most expensive path. - Changing something like
background-colortypically skips layout but still triggers paint. - Changing
transformoropacitytypically requires neither — the browser's compositor (a separate stage that combines already-painted layers) can usually apply the visual change directly, without recalculating layout or repainting pixels.
Because the compositor step is comparatively cheap and can often run
smoothly at 60 frames per second even on modest hardware, animating
transform and opacity tends to stay smooth, while animating width or
top on the same element is far more likely to visibly stutter — especially
on a page with a lot of other content that would also need to reflow around
the change.
In practice, this means: to slide an element in, animate transform: translateX(...) rather than animating left or margin-left. To fade
something in, animate opacity rather than toggling display or
visibility outright (which, as the previous lesson covered, aren't
transition-able anyway). Both approaches often produce the same visual
result, but one is built to stay smooth under animation and the other isn't.
Try it yourself
What to remember
translate(),scale(),rotate()andskew()move, resize, spin and slant an element without affecting the layout space around it.- Multiple functions in one
transformapply in the order written — reversing the order can produce a visibly different result. transform-originmoves the pivot point thatrotate()/scale()work from; the default is the element's own center.- Prefer animating
transformandopacityoverwidth,top, ormargin— the former can usually be handled by the compositor alone, without triggering layout or paint, which is what keeps an animation smooth.