Build CSS transform values and generate a CSSTRANSFORM output you can copy or download for your project.
transform: none; transform-style: preserve-3d; perspective: 600px;
translate() (move on X/Y), rotate() (spin around Z), scale() (resize), skew() (slant on X/Y), matrix() (2D composed), perspective() (3D depth field), or any of the 3D-only variants — rotateX/Y/Z(), translate3d(), scale3d(), matrix3d(). Stack as many as you need; functions compose left-to-right in the same transform declaration.<length> or <percentage> per axis (e.g., translate(50px, -20%)). Rotate takes <angle> in deg, rad, grad, or turn. Scale takes a unitless multiplier (1 = original, 0.5 = half, 2 = double). Skew takes <angle> per axis. Perspective takes a positive <length> — smaller values exaggerate the depth effect.50% 50% 0 (dead center, no Z offset). Move it to top left, 0% 100%, or any explicit <length-percentage> pair to anchor rotates and scales at a different pivot point. Preview updates live in the browser.transform: declaration (and transform-origin: if you changed it). Paste into your stylesheet, inline style= attribute, or CSS-in-JS object. No sign-up, no watermark — everything runs in your browser.transform is the workhorse for any visual effect that needs to move, rotate, resize, or 3D-project an element without re-triggering layout. Because the browser runs transforms on the compositor (GPU) rather than the main thread, they're the cheapest visual change you can apply — which makes them the right tool for hover effects, micro-interactions, parallax, modal entrances, and full-page transitions. A visual generator removes the guesswork of stacking multiple functions and lets you eyeball the result before pasting code:
transform: scale(1.05) translateY(-2px) on a card hover lifts and grows the element in one declaration; pairs cleanly with a transition: transform 150ms ease-out for the motion.translate(-50%, -50%) with the classic top: 50%; left: 50% centering pattern, then animate scale(0) → scale(1) on entry.translate3d(-Npx, 0, 0) — the 3d variant promotes the element to its own compositor layer, smoothing 60 fps swipe motion on mobile.perspective(1000px) on the parent and rotateY(180deg) on the child with transform-style: preserve-3d for the standard flip-card effect.skew(-15deg) on a background stripe with skew(15deg) on the inner text keeps the text upright while the stripe slants — a common landing-page pattern.transform: scale(var(--fit)) to letterbox content into smaller viewports without rewriting widths.When the stylesheet is ready, run it through the CSS Minifier to strip whitespace and shave bytes off your bundle, or the CSS Formatter if you'd rather keep the generated declaration pretty-printed alongside the rest of your codebase.
| Function | 2D form | 3D form | Notes |
|---|---|---|---|
| translate | translate(), translateX(), translateY() |
translate3d(), translateZ() |
The 3D variants force a new compositor layer, often used as a "GPU promotion" hint. |
| rotate | rotate() (around Z) |
rotate3d(), rotateX(), rotateY(), rotateZ() |
rotate() and rotateZ() are equivalent. |
| scale | scale(), scaleX(), scaleY() |
scale3d(), scaleZ() |
Negative values flip the element along that axis. |
| skew | skew(), skewX(), skewY() |
— none — | Skew is 2D-only; there is no skew3d() or skewZ(). |
| matrix | matrix(a,b,c,d,e,f) (6 args) |
matrix3d() (16 args) |
Tools emit these for composed transforms; almost never written by hand. |
| perspective | — | perspective(<length>) |
3D-only; smaller values = stronger depth distortion. |
transform-origin controls the pivot point for rotates and the anchor for scales. The MDN-documented initial value is 50% 50% 0 (center, no Z offset).
| Value | Pivot | Common use |
|---|---|---|
50% 50% (default) |
Dead center | Most hover scales and rotates |
top left / 0% 0% |
Top-left corner | "Unfold from corner" reveals, sidebar expansions |
bottom center / 50% 100% |
Bottom edge, horizontally centered | Tooltip pop-ups that grow up from an arrow |
0% 50% |
Left edge, vertically centered | Accordion panels sliding out from the left |
<x> <y> <z> |
Explicit pixel/percent pivot, with Z depth | Fine-tuning 3D card flips and orbiting elements |
transform describes the final state of an element. transition and animation describe how it gets there. A transform: rotate(45deg) instantly snaps the element to 45 degrees; pair it with transition: transform 300ms ease-out and a state change (e.g., :hover) to animate between two transforms. @keyframes lets you string multiple transform states together over a longer timeline. The transform itself never animates — the property that interpolates it does.
Only compositor work — transforms do not trigger layout reflow or even repaint of the transformed element's pixels. The browser hands the element off to the GPU as a composited layer and re-projects it. That's why animating transform: translateX() is dramatically cheaper than animating left: on the same element, and why transforms can hold 60 fps where layout-triggering properties drop frames.
Yes — within the single transform shorthand, functions compose left-to-right. transform: rotate(45deg) translateX(100px) first rotates the element's local coordinate system, then translates 100 px along the rotated X axis (so the element ends up diagonally offset). transform: translateX(100px) rotate(45deg) moves the element 100 px right first, then rotates in place. Different outputs, same functions. If you use the individual translate, rotate, and scale properties (separate from the shorthand), the order is fixed: translate → rotate → scale, regardless of declaration order.
translate3d(0, 0, 0) or translateZ(0) used as a performance hint?Both promote the element to its own GPU-composited layer, even when no visible 3D transform is happening. This was a common "hack" to force hardware acceleration before will-change existed, and it still works in every modern browser. Use it on elements you'll animate frequently (carousel tracks, sticky headers, modal backdrops). Don't sprinkle it on every element — each composited layer costs GPU memory.
will-change: transform — should I always add it?No. MDN explicitly warns that will-change is "intended to be used as a last resort, in order to try to deal with existing performance problems. It should not be used to anticipate performance problems." The safer pattern is to add will-change: transform via JavaScript right before an animation starts and remove it after the animation ends. Adding it permanently in a stylesheet — especially on many elements — can consume GPU memory and slow the page down rather than speed it up.
perspective() function vs perspective property vs transform-style: preserve-3d — what's the difference?The perspective() function (inside transform:) applies depth only to that single element's own transform. The perspective property applies depth to all 3D-transformed children of the element — typical pattern for a flip-card container. transform-style: preserve-3d tells the browser to render children in true 3D space rather than flattening them; without it, nested 3D transforms collapse to 2D. The classic flip-card recipe combines all three: parent gets perspective: 1000px, child gets transform-style: preserve-3d, faces get transform: rotateY(180deg) and backface-visibility: hidden.
matrix() or matrix3d() worth writing by hand?Almost never. The 6-argument matrix(a, b, c, d, e, f) and 16-argument matrix3d(...) forms encode a full affine transformation matrix, but they're not human-readable — matrix(1, 0, 0, 1, 50, 20) is just a translate, but you wouldn't know without doing the math. Tools and animation libraries (GSAP, Framer Motion, browser dev tools) emit matrix forms when they compose multiple transforms into one. If you're writing CSS by hand, stick with the named functions; if you're decoding output from a tool, that's what the matrix form is for.
scale(0.5) shrink toward the center but scale(0.5) with transform-origin: top left shrinks toward the corner?Because transform-origin defines the fixed point during a transform. Scale, rotate, and skew all pull their pivot from transform-origin. With the default 50% 50%, the element's center stays put while edges move inward. Change it to top left and the top-left corner is the anchor — the element shrinks toward that corner, leaving empty space below and to the right. This is why "scale on hover" cards sometimes look like they're sliding when really the origin is wrong.
translate, rotate, and scale properties safe to use yet?Yes for evergreen browsers — Chrome/Edge 104+, Firefox 72+, and Safari 14.1+ all support them, putting baseline coverage well into 2022. They simplify animations because you can change just the rotation without rebuilding the entire transform string, and they apply in a fixed order (translate → rotate → scale) regardless of declaration order. The catch: if you mix them with the transform shorthand on the same element, individuals apply first, then the shorthand layers on top — which can cause surprising results during refactors.