What Is CSS transform?
The transform property lets you visually move, rotate, resize, and distort elements — all without affecting the document flow. A transformed element still occupies its original space in the layout; only its rendered position changes. This makes transform ideal for animations because it never triggers a layout recalculation.
Transforms are applied in the order they are listed (right-to-left in the matrix math), which matters when combining multiple functions. transform: translateX(50px) rotate(45deg) produces a different result than rotate(45deg) translateX(50px).
2D Transform Functions
translate(), translateX(), translateY()
Moves an element along the X and/or Y axis. Values can be lengths (px, em, rem) or percentages (relative to the element's own size):
/* Move 50px right, 20px down */
.box { transform: translate(50px, 20px); }
/* Move only horizontally */
.box { transform: translateX(100px); }
/* Move only vertically */
.box { transform: translateY(-30px); }
/* Percentage: move element by 50% of its own width */
.centered {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%); /* Classic centering trick */
}
rotate()
Rotates an element clockwise by the specified angle. Negative values rotate counter-clockwise:
/* Rotate 45 degrees clockwise */
.icon { transform: rotate(45deg); }
/* Counter-clockwise rotation */
.icon { transform: rotate(-90deg); }
/* Fractional turns (1turn = 360deg) */
.icon { transform: rotate(0.25turn); }
/* Using radians */
.icon { transform: rotate(1.5708rad); /* π/2 = 90deg */
scale(), scaleX(), scaleY()
Resizes an element relative to its transform-origin. A value of 1 is original size; 2 is double; 0.5 is half. Negative values flip the element:
/* Scale up uniformly */
.card:hover { transform: scale(1.05); }
/* Scale horizontally only */
.progress { transform: scaleX(0.6); }
/* Flip horizontally */
.mirror { transform: scaleX(-1); }
/* Flip vertically */
.flip { transform: scaleY(-1); }
skew(), skewX(), skewY()
Tilts an element along the X and/or Y axis, creating a parallelogram effect:
/* Skew 20 degrees along X axis */
.badge { transform: skewX(-20deg); }
/* Skew both axes */
.shape { transform: skew(10deg, 5deg); }
matrix()
The matrix() function combines all 2D transforms into a single 6-value matrix. It's rarely written by hand but is what the browser uses internally:
/* matrix(scaleX, skewY, skewX, scaleY, translateX, translateY) */
.box {
transform: matrix(1, 0.2, 0, 1, 50, 30);
/* Equivalent to: skewY(0.2) + translateX(50px) + translateY(30px) */
}
transform-origin: Changing the Pivot Point
By default, transforms originate from the element's center (50% 50%). transform-origin changes this pivot point:
/* Rotate from top-left corner */
.fold { transform-origin: top left; transform: rotate(-5deg); }
/* Scale from bottom */
.grow { transform-origin: bottom center; transform: scale(1.2); }
/* Numeric values */
.box { transform-origin: 20px 80%; }
3D Transform Functions
CSS 3D transforms add depth along the Z-axis. To see 3D effects, you must set perspective on the parent container.
Setting Up Perspective
/* Apply perspective to the parent (scene container) */
.scene {
perspective: 800px; /* Smaller value = more dramatic 3D */
perspective-origin: 50% 50%;
}
/* Or use the perspective() function inline on the element */
.box {
transform: perspective(600px) rotateY(45deg);
}
rotateX(), rotateY(), rotateZ()
/* Flip card effect — rotate around Y axis */
.card-front { transform: rotateY(0deg); }
.card-back { transform: rotateY(180deg); }
/* Tilt forward/backward */
.board { transform: rotateX(20deg); }
translate3d() and translateZ()
/* Move along Z axis (toward/away from viewer) */
.popup { transform: translate3d(0, 0, 50px); }
/* Equivalent to translateZ */
.popup { transform: translateZ(50px); }
scale3d() and scaleZ()
/* Scale along all three axes */
.cube-face { transform: scale3d(1, 1, 0.5); }
matrix3d()
A 4×4 matrix covering all 3D transformations. Its 16 values make it impractical to write by hand — use it when receiving matrix data from WebGL or animation libraries.
transform-style: preserve-3d
When building nested 3D elements (like a cube), child elements must inherit the 3D space. Set transform-style: preserve-3d on the parent:
.cube {
transform-style: preserve-3d;
animation: rotateCube 4s linear infinite;
}
@keyframes rotateCube {
from { transform: rotateY(0deg) rotateX(0deg); }
to { transform: rotateY(360deg) rotateX(360deg); }
}
.face {
position: absolute;
width: 100px;
height: 100px;
}
.front { transform: translateZ(50px); }
.back { transform: rotateY(180deg) translateZ(50px); }
.left { transform: rotateY(-90deg) translateZ(50px); }
.right { transform: rotateY(90deg) translateZ(50px); }
.top { transform: rotateX(90deg) translateZ(50px); }
.bottom { transform: rotateX(-90deg) translateZ(50px); }
Practical Transform Patterns
Perfect Centering with translate
.modal {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
/* Works regardless of modal width/height */
}
Flip Card with rotateY
.card-container {
perspective: 1000px;
}
.card {
width: 200px;
height: 300px;
position: relative;
transform-style: preserve-3d;
transition: transform 0.6s ease;
}
.card:hover {
transform: rotateY(180deg);
}
.card-front,
.card-back {
position: absolute;
inset: 0;
backface-visibility: hidden;
}
.card-back {
transform: rotateY(180deg);
}
Hover Scale with transform-origin
.nav-link {
display: inline-block;
transition: transform 0.15s ease;
transform-origin: center bottom;
}
.nav-link:hover {
transform: scale(1.1);
}
How transform Affects Layout
A critical point: transforms do not affect layout. Other elements in the document are completely unaware of a transformed element's visual position. A translateX(200px) moves the element visually but its original space is preserved in the flow. This is why transform is the preferred method for animation — no other elements shift or reflow when it changes.
This also means overlapping is possible. Plan your z-index accordingly when elements might overlap due to transforms.
Individual Transform Properties (Modern CSS)
Modern CSS allows you to specify transform components as separate properties instead of in one transform declaration. This is a game-changer for animations:
/* Old way — animating two transforms requires a single keyframe */
@keyframes old {
from { transform: translateY(20px) scale(0.9); }
to { transform: translateY(0) scale(1); }
}
/* New way — animate each property independently */
.element {
translate: 0 20px;
scale: 0.9;
transition: translate 0.3s ease, scale 0.3s ease 0.1s;
}
.element:hover {
translate: 0 0;
scale: 1;
}
Individual transform properties (translate, rotate, scale) have full browser support in modern browsers and make it much easier to combine transforms in animations independently.
Experiment with all transform functions using our Live HTML/CSS/JS Editor — paste any of the examples above and see instant results.