1 · the v4 split: individual properties vs transform
In v3, every transform utility fed one transform: translate() rotate() scale()
— so the order you wrote classes changed the result. v4 split this:
2D rotation/scale/translation now compile to the modern individual CSS properties
(rotate:, scale:, translate:), which compose
independently regardless of class order. Only 3D rotation (rotateX/Y/Z) and
skew still use the transform property — CSS has no individual
equivalents for those yet. The gold-check above proves exactly this split live.
| family | Tailwind v4 class | compiles to | which CSS property |
|---|---|---|---|
| 2D rotate | rotate-45 |
rotate: 45deg |
individual rotate (not transform) |
| 2D scale | scale-110 |
scale: 1.1 1.1 |
individual scale |
| 2D translate | translate-x-4 |
translate: 1rem 0 |
individual translate |
| skew | skew-x-12 |
transform: matrix(...) |
transform (no individual skew prop) |
| 3D rotate | rotate-x-45 |
transform: rotateX(45deg) var(--tw-rotate-y) |
transform (pulls in --tw-rotate-* vars) |
| 3D translate | translate-z-12 |
transform: translateZ(0.75rem) |
transform |
Practical consequence: combine rotate-45 scale-110 translate-x-4 in any
order in v4 — they never overwrite each other because they target three different
properties. In v3, swapping the class order changed the visual result.
2 · 3D rotation playground — rotate-x / rotate-y / rotate-z + perspective
Drag the sliders to rotate the cube on each axis and move the camera (perspective).
Three ingredients stack: the .stage wrapper sets
perspective (camera distance), the .cube sets
transform-style: preserve-3d (= Tailwind transform-3d) so the six
faces stay in 3D space, and each face is rotated/translated into position. Without
perspective the cube renders flat-orthogonal; without preserve-3d it flattens.
computed transform: —
3 · perspective = camera distance (near vs distant)
perspective goes on the parent and sets the vanishing point. A small value
(near / dramatic) is a close camera — strong foreshortening, big depth. A large value
(distant) is a far camera — subtle, almost orthographic. Below, the same
rotate-y-45 tile is shown under three perspective presets.
| utility | value | feel |
|---|---|---|
perspective-dramatic | 100px | extreme close-up, max warping |
perspective-near | 300px | obvious 3D depth |
perspective-normal | 500px | balanced default |
perspective-midrange | 800px | mild depth |
perspective-distant | 1200px | near-orthographic, subtle |
perspective-[1000px] | arbitrary | any exact value |
perspective-near (300px)
perspective-normal (500px)
perspective-distant (1200px)
Notice the near tile foreshortens hard (left edge stretches), the distant tile barely
narrows. Same rotate-y-45 — only the camera moved.
4 · 3D flip card (hover) — transform-3d + backface-hidden
The classic flip card needs four pieces: a group parent with
[perspective:1000px], an inner panel with transform-3d
(preserve-3d) that group-hover:rotate-y-180s, and two faces that are
backface-hidden (so you never see the reversed mirror of the other side). The back
face is pre-rotated rotate-y-180 so it sits correctly behind the front.
Hover the card. backface-hidden = backface-visibility: hidden —
crucial: without it, the front face's mirror bleeds through during the flip.
5 · 2D transform zoo — rotate · scale · skew · translate
Hover each tile. These all use the v4 individual properties (rotate:,
scale:, translate:) — except skew, which still uses
transform. Pair them with transition + duration-300 for the motion.
hover:rotate-45
hover:scale-125
hover:skew-x-12
hover:translate-x-4
hover:-scale-100
rotate-12 + scale-110
intent → pattern
| intent | pattern | why |
|---|---|---|
| spin a 2D element | rotate-45 |
sets individual rotate: — composes with scale/translate freely |
| flip on hover (mirror) | hover:-scale-100 |
negative scale flips; -scale-x-100 for horizontal only |
| give a 3D child real depth | parent perspective-[1000px] + child rotate-x-45 |
perspective on PARENT; without it 3D rotation looks flat |
| nest 3D children | transform-3d on the middle wrapper |
transform-style: preserve-3d — default flat squashes children |
| flip card | transform-3d + backface-hidden + group-hover:rotate-y-180 |
backface-hidden prevents the mirror bleeding through |
| animate a transform | transition-[transform,rotate,scale,translate] duration-300 |
v4 individual props are separate — name them all, or use transition-all |
| custom axis rotation | rotate-x-[18deg] |
arbitrary value for any non-preset degree |