Skip to content
AgileLogics
5 min read

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.