CSS: Transforms

Move, rotate, scale, and skew elements in 2D and 3D without affecting page layout.

transform: translate()

translate() moves an element from its current position. Crucially, the original space is preserved, surrounding elements are not affected, unlike changing margin or top/left.

translate()

translate moves an element visually without changing the layout. This makes it safe to use in animations, nothing else on the page shifts.

  • translateX(50px): moves 50px to the right (negative = left)
  • translateY(20px): moves 20px down (negative = up)
  • translate(50px, 20px): moves 50px right and 20px down
  • translate(-50%, -50%): the classic centering trick: offset by half the element's own size
  • Percentage values are relative to the element's own size, not the parent

translate()

The middle element moves right but the layout of other elements is unchanged.

transform: rotate()

rotate() spins an element around its origin point. Positive values rotate clockwise; negative values rotate counter-clockwise. The unit is degrees (deg), turns (turn), or radians (rad).

rotate()

By default, rotation happens around the center of the element. Change transform-origin to rotate around a corner or edge instead.

  • rotate(45deg): 45° clockwise
  • rotate(-90deg): 90° counter-clockwise
  • rotate(0.25turn): 90° clockwise (1 turn = 360°)
  • rotate(1rad): approximately 57° clockwise
  • Rotation does not affect layout, the element's original space stays occupied

rotate()

Four boxes rotated at increasing angles from a shared center point.

transform: scale()

scale() resizes an element. A value of 1 is the original size, 2 is double, and 0.5 is half. Like all transforms, it does not affect the surrounding layout.

scale()

scale() visually resizes the element without changing its layout footprint. It is GPU-accelerated and far more performant than animating width or height.

  • scale(1.2): 20% larger than original (same on both axes)
  • scale(0.5): half the original size
  • scaleX(2): doubles width only
  • scaleY(0.5): halves height only
  • scale(1.5, 0.8): 1.5× wide, 0.8× tall
  • Negative scale values flip the element: scaleX(-1) creates a mirror image

scale()

Three boxes at different scale values, the layout space stays the same for all.

transform: skew()

skew() tilts an element along its horizontal or vertical axis, creating a slanted or parallelogram effect. It is used for decorative shapes and diagonal layouts.

skew()

skew() distorts the element's shape. It is mainly used for visual decoration: slanted banners, diagonal section dividers, and italic-style shapes.

  • skewX(20deg): slants the element along the X axis
  • skewY(10deg): slants the element along the Y axis
  • skew(20deg, 10deg): skews both axes at once
  • Counter-skew the content inside to keep text readable: apply the opposite skew to the child

skew()

The banner is skewed to create a diagonal shape; the text inside is counter-skewed to stay straight.

transform-origin

transform-origin sets the point around which transforms are applied. By default it is the center of the element (50% 50%). Changing it lets you rotate from a corner, scale from an edge, or create hinge effects.

transform-origin

transform-origin accepts keywords (top, left, center, bottom, right), percentages, or length values. It accepts an X value and optionally a Y value.

  • transform-origin: center: default; rotates around the middle of the element
  • transform-origin: top left: rotates from the top-left corner
  • transform-origin: bottom center: rotates from the bottom edge center
  • transform-origin: 0% 100%: same as bottom left using percentages
  • Affects rotate, scale, and skew, not translate

transform-origin

Three boxes rotated 45deg, each pivots from a different origin point.

3D Transforms (perspective, rotateX/Y/Z)

CSS supports 3D transforms that move and rotate elements in three dimensions. The perspective property on the parent sets the depth of the 3D view: how far the viewer is from the scene.

3D Transforms

perspective is set on the parent container, not on the element itself. A smaller perspective value creates a more extreme 3D effect; larger values appear flatter.

  • perspective: 600px: set on the parent; creates the 3D viewing distance
  • rotateX(deg): tilts the element forward/back (around the horizontal axis)
  • rotateY(deg): spins the element left/right (around the vertical axis)
  • rotateZ(deg): rotates in the plane of the screen (same as rotate())
  • translateZ(px): moves the element toward or away from the viewer
  • transform-style: preserve-3d: on the parent, keeps children in 3D space

3D rotates

Two cards rotated on different 3D axes inside a perspective container.

Combining Multiple Transforms

Multiple transform functions are applied in a single transform declaration, separated by spaces. The order matters, transforms are applied right to left, so the last function listed is applied first.

Combining transforms

Never write two separate transform declarations: the second will overwrite the first. Always combine them in one declaration separated by spaces.

  • transform: rotate(45deg) scale(1.2): rotates then scales (scale is applied first)
  • transform: translateX(50px) rotate(30deg): translate then rotate
  • Order matters: translate(50px, 0) rotate(45deg) is different from rotate(45deg) translate(50px, 0)
  • Avoid writing two transform properties: the second overwrites the first completely

Combined transforms

Both boxes use two transforms in a single declaration.

Performance Benefits of Transforms

The browser rendering pipeline has three stages: layout, paint, and composite. Transforms and opacity skip the first two stages entirely and run only at the composite stage, directly on the GPU. This is why they stay smooth even on slower devices.

Why transforms are fast

Animating properties like width, height, top, or left triggers layout on every frame: the browser must recalculate positions of every surrounding element. Transforms never do this.

  • transform + opacity: GPU-accelerated; skip layout and paint; always smooth
  • color, background-color: trigger repaint only; generally fine for UI
  • width, height, top, left, margin: trigger full layout recalculation every frame; avoid animating
  • will-change: transform: hints the browser to promote the element to its own GPU layer before the animation starts
  • Use translateX/Y instead of left/right, scaleX/Y instead of width/height

Performance comparison

Both slide on hover, but only the second is GPU-accelerated and jank-free.

Knowledge Check

1. What does transform: translateX(50px) do?

2. What does transform: scale(0.5) do?

3. What is the default transform-origin value?

4. Which property is needed on a parent to create a 3D perspective effect for children?

5. When combining multiple transforms, what is the correct syntax?

6. Why is transform preferred over top/left for moving elements?