Command Palette

Search for a command to run...

Hectal
Shots in this scene
SHOT 4.1Beginner ~22 min · shot 1 of 6

Transforms for Motion

In one line

translate, scale and rotate move, resize and turn an element without changing the page layout. The order of the functions changes the result, the individual properties have a fixed order, and a few elements (inline boxes, SVG shapes) behave differently.

0/6 · 0%

Think of it like this

A photo lying on a desk. You can slide it, turn it or move it nearer without changing what is printed on it, and the other things on the desk stay where they are. A CSS transform does this to an element: the page is laid out as if nothing happened, then the element is drawn moved, turned or scaled. (The CSS course's Topic 10.2 introduced the functions. Here we go deeper, because transforms are what animations move.)

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

transform
A CSS property that moves, turns, resizes or slants an element's picture without changing the page layout.
transform function
One step of a transform list, such as translateX(60px) or rotate(45deg).
transform-origin
The point that rotating and scaling pivot around. The middle of the element by default.
layout
The browser's work of deciding where every element goes and how big it is. Transforms skip it.
inline box
An element that flows inside a line of text, like a <span> or <a>. It has no box of its own to transform.
transform-box
For SVG shapes: which box the origin refers to. view-box is the whole drawing (the default), fill-box is the shape itself.

Step by step

01Two lists, two results

Press Go in the first example. Box A (translate, then rotate) slides straight right and turns. Box B (rotate, then translate) ends lower. Same two functions, written in the other order.

Pause, slow it to 0.1× and step to 350 ms: A is at x 30, y 0. B is at x 27.7, y 11.5. B leaves the straight line at once, because the turn bends the direction its translation points.

02Separate properties are separate tracks

Box C uses translate and rotate. On the timeline it has two tracks, translate and rotate, where A and B have one transform track each. Each property is animated on its own and ends in the same place as A.

A transition names the property it animates. transition: transform does not cover translate: change translate and the box jumps (the first break-it).

03The origin decides where it pivots

In the second example press Rotate 45°. The "centre" pad turns on the spot. The "corner" pad has transform-origin: 0 0, so it swings around its top-left corner and leans into its neighbour.

04Some things cannot be transformed

The page logs inl moved by 0 px for the inline span and blk moved by 40 px for the same span made inline-block. Same transform, different box type.

In the SVG, the first square (default origin) rotates around the top-left corner of the drawing and is mostly cut off. The second (fill-box) turns in place.

Try it yourself

  1. 1

    Follow the curve

    In "Order matters", press Go, pause, set 0.1× and step to about 350 ms. Read A: (30, 0). Read B: (27.7, 11.5). Step on to the end: A is at (60, 0), B at (42.4, 42.4). B's track is the same length and the same easing as A's. Only the order of its functions differs.

  2. 2

    Make A behave like B

    In the CSS, change .far #a to transform: rotate(45deg) translateX(60px);. Press Run, then Go. Box A now takes B's route and ends at (42.4, 42.4). The order of the two words was the whole difference.

  3. 3

    Pivot around a corner

    In the second example, delete #o2 { transform-origin: 0 0; } and press Rotate 45° again. Both pads now turn on the spot, and the overlap is gone.

Code & diagrams

Order matters

Press Go, then pause and step. A and C end in the same place; B ends 42.4 px lower. C is built from the individual properties, so it has two tracks.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.
The individual properties apply in a fixed ordercss
/* the same result: translate, then rotate, whatever order you write them in */
.a { translate: 60px 0; rotate: 45deg; }
.b { rotate: 45deg; translate: 60px 0; }

/* the transform list is applied after them: scale(2) here is the last step */
.c { rotate: 45deg; translate: 60px 0; transform: scale(2); }
Where transforms do not work, and the origin

The log is the same on every run. Press Rotate 45° and compare the two pads and the two squares.

Press Run to see the page.
00:00.000
animations
0.00s0.10s0.20s0.30s0.40s0.50s0.60s0.70s0.80s0.90s

Nothing is moving yet. Hover, click or scroll the page: every animation it starts shows up here as a track.

frames

Console

Nothing logged yet.

Expected console output

inl moved by 0 px
blk moved by 40 px

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Change translate, transition only transform

In "Order matters", change the transition line to transition: transform 700ms ease-in-out; (delete the translate and rotate parts). Press Run, then Go.

terminal
$ Press Go and read box C at 500 ms
── what you'll see ──
C is already at its end position (60 px across, turned 45°) the instant you press Go. The timeline shows tracks for A and B only.
Measured: with only `transition: transform`, `translate` reads 100px at 500 ms (its end value) and no `translate` or `rotate` track exists.

Break #2

Transform an inline element

In the second example, delete the rule #blk { display: inline-block; }. Press Run.

terminal
$ Console
── what you'll see ──
inl moved by 0 px
blk moved by 0 px
Captured from a real run: with `display: inline-block` removed, the same transform moves it by 0 px.

Myth vs fact

Myth

translateX(60px) rotate(45deg) and rotate(45deg) translateX(60px) are the same.

Fact

They are not. Each function works in the space the earlier ones made, so rotating first turns the direction of the move. Box B ends 42.4 px lower than box A.

Myth

A transform moves the element, so the layout updates around it.

Fact

The layout box never moves. Neighbours stay where they were, and the old space stays empty. Only the drawing (and where clicks land) moves.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    Function lists with matching functions interpolate function by function: translateX(0) rotate(0) to translateX(60px) rotate(45deg) moves in a line while turning. If the lists do not match (different functions or order), the browser falls back to interpolating whole matrices, which can look odd. Keep the same functions in the same order in every state you animate between.

  • ▸

    Transforms are hit-tested as drawn, so a button moved with translate is clickable in its new place, and a button that slides away with scale(0) is not. Pair a hiding transform with visibility or inert so a hidden element cannot be focused with the keyboard.

  • ▸

    The layout box not moving also means scrollable overflow still counts transformed content, and a translateX(100%) panel off the right edge can create a horizontal scrollbar. Use overflow: clip on the parent, or a transform on a fixed-position panel.

Remember this

  1. 1

    The problem this solves: to move something you could change left, top or width. Each of those changes the layout, so the browser must work out the position of other elements again on every frame. A transform leaves the layout alone and only changes how the finished element is drawn, which is far cheaper (Phase 6 measures it). It is the property most animations should move.

  2. 2

    The functions. translate(x, y) moves (translateX(60px) moves right). scale(1.5) resizes around the origin point. rotate(45deg) turns clockwise. skew() slants. You write them in the transform property, one after another, as a list: transform: translateX(60px) rotate(45deg).

  3. 3

    Order matters. Each function works in the coordinate system the functions before it made. In translateX(60px) rotate(45deg) the element moves 60 px right, then turns on the spot. In rotate(45deg) translateX(60px) it turns first, which turns its own x-axis, so 60 px "to the right" now points down and to the right. The first box (A) ends 60 px to the right. The second (B) ends 42.4 px right and 42.4 px down. Try both in the first example.

  4. 4

    The individual properties. translate, rotate and scale are properties of their own, so translate: 60px 0; rotate: 45deg works without a list. The browser always applies them in the order translate, rotate, scale, and only then the transform list, however you write them. That makes them safe to animate separately: one animation can move translate while another turns rotate (Topic 4.5 uses this). They are Baseline widely available (MDN, checked October 2026: since August 2022, about Chrome 104, Firefox 72, Safari 14.1).

  5. 5

    The origin. Rotating and scaling happen around a point, transform-origin, which is the middle of the element by default. transform-origin: 0 0 pivots around the top-left corner instead. Percentages in translate are percentages of the element itself: translateX(100%) moves a 30 px box 30 px and a 200 px box 200 px. That is why translateX(-100%) hides a panel just off its own left edge, whatever its width.

  6. 6

    Where transforms do not work. An inline box such as a <span> in a line of text ignores transforms: it has no box of its own to move. Give it display: inline-block. SVG shapes behave differently: their default origin is the top-left of the whole SVG, not the shape's middle, so a rotated shape swings away. transform-box: fill-box plus transform-origin: center brings the origin back to the shape.

  7. 7

    What a transform does not change. The layout box stays where it was, so neighbours do not move. Clicks, though, follow what you see: the moved element receives them in its new place. A transformed element also becomes a stacking context and the containing block for position: fixed children.

Explain it without notes

01

Why is a transform cheaper to animate than left?

02

What is the difference between translateX(60px) rotate(45deg) and rotate(45deg) translateX(60px)?

03

Why does a rotated SVG <rect> sometimes swing out of its drawing, and how do you fix it?

Practice

01

Make a card slide in from the right and tilt back to straight: it starts at translate: 40px 0; rotate: 4deg and ends at none. Use the individual properties and a transition on both.

02

Make an arrow icon (a <span>) rotate 90° when a menu opens. It currently ignores the transform. Explain why and fix it.

Done when you can

  • You can say where the box ends for any list of translate and rotate, in either order

  • You know the individual properties apply in the order translate, rotate, scale, then transform

  • You can change the origin, and you know it is the middle by default

  • You know inline boxes ignore transforms and how SVG shapes differ