What transform does
transform changes how an element is drawn: moved, scaled, rotated or slanted. The dashed outlines below show where each box would be without its transform:
translate(20px, 10px) moves the blue box 20px along and 10px down. scale(1.3) makes the green one 30% bigger around its center. rotate(20deg) turns the amber one clockwise, and skewX(-20deg) slants the dark one. In every case the dashed slot, which is the space the element takes in the layout, stays exactly where it was.
Transform functions
| Function | Does | Example |
|---|---|---|
translate(x, y) | moves | translate(20px, -10px), translate(-50%, -50%) |
translateX(x) / translateY(y) | moves on one axis | translateY(-4px) |
scale(s) / scale(x, y) | resizes (1 = original, 0.5 = half, negative mirrors) | scale(1.1), scale(-1, 1) |
scaleX(s) / scaleY(s) | resizes on one axis | scaleX(0.5) |
rotate(angle) | turns clockwise (negative = counterclockwise) | rotate(45deg), rotate(0.25turn) |
skew(x, y) / skewX(a) / skewY(a) | slants | skewX(-15deg) |
matrix(a, b, c, d, e, f) | all of the above in one matrix, mostly what the browser reports back | |
none | no transform |
Percentages in translate() are relative to the element's own size, not its parent's. Rotation has its own page with degrees, turns and spinning: CSS rotate.
Transform playground
Move the sliders. The first line is the transform value you built; the second is the matrix the browser computed from it, which is what getComputedStyle returns for any transform:
Transforms do not move the layout
A transformed element is drawn somewhere else, but the page is laid out as if it were not transformed. Its neighbors keep their positions. This is what makes transforms good for hover effects and animation: nothing around them reflows.
Both middle boxes look 1.5 times bigger. The scaled one overlaps its neighbors and C stays put; the one made bigger with width and height pushes C 40px further along.
Multiple transforms and their order
Put several functions in one transform, separated by spaces. The order changes the result, because, read from left to right, each function works in the coordinate system left behind by the functions before it:
The blue box moved 120px straight along and was then turned in place. The green box was turned first, so its "x axis" points diagonally, and translateX(120px) moves it down the diagonal. Same functions, different place.
The other trap: a second transform declaration replaces the first. If a card has transform: rotate(-2deg) and its hover rule says transform: scale(1.05), the rotation disappears on hover. Repeat both (rotate(-2deg) scale(1.05)), or use the individual properties below.
transform-origin
Scaling, rotating and skewing happen around a fixed point, the transform origin, which is the center by default. Change it with keywords, lengths or percentages:
All three boxes turn 25 degrees. The first pivots on its middle, the second keeps its top-left corner pinned to the slot's corner, the third its bottom-right corner. A dropdown menu that grows out of its button uses transform-origin: top with scale().
The translate, scale and rotate properties
Modern browsers also have three separate properties that do the same thing as the functions, but can be set and animated independently:
.card {
rotate: -2deg;
transition: scale 0.2s ease-out;
}
.card:hover {
scale: 1.05; /* the rotation stays, because it is a different property */
}
They always combine as if written transform: translate(...) rotate(...) scale(...) in front of any transform value, whatever order you declare them in. Note the syntax: translate: 10px 20px and scale: 1.2 take values without the function parentheses.
Centering with translate(-50%, -50%)
Because translate() percentages refer to the element's own size, top: 50%; left: 50%; transform: translate(-50%, -50%) centers an absolutely positioned element of any size in its parent. The center a div page compares it with flexbox and grid.
Common mistakes
- Two
transformdeclarations. The later one wins entirely. Combine the functions, or use therotate,scaleandtranslateproperties. - Transforming an inline element. A plain
<span>or<a>ignorestransform. Make itinline-block. - Expecting neighbors to move. Transforms never change the layout. To make space, change
width,marginorgap. - Wrong function order.
rotate()beforetranslate()moves along the rotated axis. - Surprises with
position: fixedchildren. A transformed element becomes the containing block for fixed-position descendants, so a fixed header inside it scrolls with it. It also creates a new stacking context forz-index.
Frequently Asked Questions
What does transform do in CSS?
It changes how an element is drawn: moved (translate), resized (scale), turned (rotate) or slanted (skew). The element keeps its original place in the layout, so the elements around it do not move.
How do I apply multiple transforms in CSS?
List them in one transform value separated by spaces: transform: translateX(50px) rotate(20deg) scale(1.2);. Writing a second transform declaration replaces the first one instead of adding to it.
Does the order of transform functions matter?
Yes. Read from left to right, each function works in the axes the previous ones left behind, so rotate(45deg) translateX(100px) moves the element along a rotated axis, while translateX(100px) rotate(45deg) moves it straight and then turns it.
What is transform-origin?
The fixed point that scaling, rotating and skewing happen around. The default is the center (50% 50%). transform-origin: top left makes an element grow from, or turn around, its top-left corner.
Why does transform not work on my span?
Transforms do not apply to non-replaced inline elements such as a plain <span> or <a>. Give the element display: inline-block or block and the transform works.