Himanshu SharmaSoftware engineer
Let’s talk

CSS · Lesson 26 of 29

Transforms

Move, scale, rotate and skew elements with the CSS transform property, understand transform-origin, combine transforms, and create 3D effects with perspective.

12 minPolishUpdated 18 October 2026

By the end of this lessonUse translate, scale, rotate and skew to change how an element looks without moving its neighbours, and set the origin and order correctly.

Changing how an element is drawn

The transform property changes the way an element is drawn without changing the layout around it. You can move it, resize it, turn it, tilt it. The element's original space remains reserved, so nothing else on the page shifts, which makes transforms ideal for effects and animation.

html
<style>
  .row { display: flex; gap: 40px; padding: 30px; }
  .box { width: 70px; height: 70px; background: #6366f1; color: white; display: grid; place-items: center; border-radius: 8px; }
  .t1 { transform: translate(20px, 14px); }
  .t2 { transform: scale(1.4); }
  .t3 { transform: rotate(20deg); }
  .t4 { transform: skewX(-15deg); }
</style>
<div class="row">
  <div class="box t1">move</div>
  <div class="box t2">scale</div>
  <div class="box t3">rotate</div>
  <div class="box t4">skew</div>
</div>

The 2D functions

  • translate(x, y): move. translateX() and translateY() do one direction. Percentages refer to the element's own size, which makes translate(-50%, -50%) a famous centring trick.
  • scale(n): resize; 1 is normal, 0.5 is half, 1.2 is 20 percent bigger. scaleX() and scaleY() stretch in one direction.
  • rotate(angle): turn clockwise by degrees (45deg), turns (0.25turn) or radians. Negative values turn the other way.
  • skew(x, y): slant the element.

Because transforms leave neighbours alone, a scaled-up card overlaps what is next to it rather than pushing it.

Combining transforms

List several functions in one declaration, separated by spaces:

css
.card:hover { transform: translateY(-4px) rotate(2deg) scale(1.03); }

Order matters: they are applied right to left, in terms of the element's coordinate system, so rotate(45deg) translateX(100px) and translateX(100px) rotate(45deg) end up in different places. When the result is surprising, reorder.

Note also that setting transform replaces any earlier transform on that element rather than adding to it. If a hover rule only says scale(1.1), a rotate(5deg) from the base rule is dropped. Repeat the whole list, or use the individual properties below.

Individual properties

Modern browsers also support separate translate, rotate and scale properties, which combine without overwriting each other:

css
.icon { rotate: 15deg; scale: 1.1; translate: 0 -2px; }

transform-origin

Scaling and rotation happen around a point, by default the centre (50% 50%). Change it with transform-origin:

html
<style>
  .bar { width: 120px; height: 14px; background: #ef4444; margin: 40px; transition: transform .6s; }
  .bar.left { transform-origin: left center; }
  .bar:hover { transform: scaleX(0.4); }
</style>
<div class="bar left">hover</div>
<div class="bar">hover</div>

The first bar shrinks toward its left edge; the second shrinks toward its centre. This is how progress bars and "swing open" menus are built: transform-origin: top center for a dropdown, top left for a door-like hinge.

Centring with transforms

Before Flexbox and Grid, this was the usual way to centre an absolutely positioned element:

css
.modal { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); }

top and left move the element's top-left corner to the centre of the parent; the translate pulls it back by half its own width and height. It still works, but place-items: center on a grid parent is simpler.

A taste of 3D

Add perspective to the parent, then rotate on the X or Y axis:

html
<style>
  .scene { perspective: 400px; padding: 40px; }
  .card { width: 120px; height: 80px; background: #f59e0b; color: white; display: grid; place-items: center;
          border-radius: 8px; transition: transform .5s; }
  .card:hover { transform: rotateY(50deg); }
</style>
<div class="scene"><div class="card">flip</div></div>

Smaller perspective values exaggerate depth. Fully flipping a card needs transform-style: preserve-3d and backface-visibility: hidden on its faces. Use 3D sparingly; it is easy to make text blurry or unreadable.

Things to know

  • A transform creates a stacking context and a containing block for position: fixed children, which can break fixed headers inside transformed parents.
  • Text and thin lines can look blurry at fractional pixel translations or with 3D. Round values where you can.
  • Inline elements (span) cannot be transformed until they are display: inline-block or block.
  • Transforms are not announced to assistive technology; they are purely visual. Do not use them to convey meaning.
  • Combine with transition for hover effects, or @keyframes for continuous ones (next lessons).

Common mistakes

  • Overwriting an earlier transform with a new transform declaration.
  • Wrong order of combined functions.
  • Expecting the layout to adjust to a scaled element.
  • Transforming an inline element that ignores it.
  • Forgetting transform-origin when rotating or scaling from an edge.

Exercise

Make a card that tilts 3 degrees and rises 6px on hover, scaled up by 3 percent, with a smooth 0.2s transition. Then set a different origin for a "door" that opens from the left.

Show one possible answer
html
<style>
  .card { width: 200px; padding: 20px; background: #e0f2fe; border-radius: 12px; transition: transform .2s ease-out; }
  .card:hover { transform: translateY(-6px) rotate(-3deg) scale(1.03); }
  .door { width: 120px; height: 160px; background: #92400e; transform-origin: left center; transition: transform .5s; }
  .door:hover { transform: perspective(500px) rotateY(-60deg); }
</style>
<div class="card">Tilt card</div>
<div class="door"></div>

Key points

  • transform changes an element's appearance - translate moves it, scale resizes it, rotate turns it and skew slants it.
  • Transforms do not affect layout, so other elements stay where they were.
  • Several transforms in one declaration apply right to left, so the order changes the result.
  • transform-origin sets the point that scaling and rotation happen around, and it defaults to the centre.
  • Transforms are cheap for the browser, which makes them the right choice for animation.

Check yourself

1. Do other elements move out of the way when you translate an element?
2. What does transform: scale(1.5) do?
3. Where does rotation happen by default?
4. Why is transform better than top and left for animation?

Free tools for this lesson