transform-origin
Setting the origin for an element’s transformations.
Overview
| Class | Declarations |
|---|---|
transform-origin:top | transform-origin: top;
|
transform-origin:bottom | transform-origin: bottom;
|
transform-origin:right | transform-origin: right;
|
transform-origin:left | transform-origin: left;
|
transform-origin:center | transform-origin: center;
|
transform-origin:<value> | transform-origin: <value>;
|
transform-origin:<offset-x>|<offset-y> | transform-origin: <offset-x> <offset-y>;
|
transform-origin:<offset-x>|<offset-y>|<offset-z> | transform-origin: <offset-x> <offset-y> <offset-z>;
|
Examples
Set the pivot point
Compare the same 75% scale around the center and the top-left corner. Violet points mark each pivot outside the transformed layer.
<!-- Center · four edges move inward --><div class="p-lg"> <div class="rel h:96px w:160px outline:1px|dashed|var(--color-line-muted)"> <div id="target" class="grid place-items:start|center h:96px w:160px p-sm b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 transform:scale(.75) transform-origin:center"> Center pivot </div> <span aria-hidden="true" class="abs left:77px top:45px width:6px height:6px r:100% bg-violet-60 untouchable"></span> </div></div><!-- Top left · two edges stay fixed --><div class="p-lg"> <div class="rel h:96px w:160px outline:1px|dashed|var(--color-line-muted)"> <div id="target" class="grid place-items:start|center h:96px w:160px p-sm b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 transform:scale(.75) transform-origin:top|left"> Corner pivot </div> <span aria-hidden="true" class="abs left:-3px top:-3px width:6px height:6px r:100% bg-violet-60 untouchable"></span> </div></div>Generated CSS
@layer utilities { .transform-origin\:center { transform-origin: center }}The transform is identical in both examples. Only the pivot changes. Origin percentages refer to the transform reference box; the usual HTML border box is 160 × 96 here.
Use two-axis origins
The first coordinate is horizontal and the second is vertical. Compare a top-right keyword pair with the explicit point 25% across and 75% down.
<!-- Top right · 160px, 0px --><div class="p-lg"> <div class="rel h:96px w:160px outline:1px|dashed|var(--color-line-muted)"> <div id="target" class="grid place-items:center h:96px w:160px p-sm b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 transform:scale(.75) transform-origin:top|right"> Top-right pivot </div> <span aria-hidden="true" class="abs right:-3px top:-3px width:6px height:6px r:100% bg-violet-60 untouchable"></span> </div></div><!-- 25% 75% · 40px, 72px --><div class="p-lg"> <div class="rel h:96px w:160px outline:1px|dashed|var(--color-line-muted)"> <div id="target" class="grid place-items:center h:96px w:160px p-sm b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 transform:scale(.75) transform-origin:25%|75%"> Offset pivot </div> <span aria-hidden="true" class="abs left:37px top:69px width:6px height:6px r:100% bg-violet-60 untouchable"></span> </div></div>Use | for spaces inside a class value. Percentage offsets use the selected reference box. A third origin value, when needed for 3D transforms, is a length along the Z axis.
Match the origin to the interaction
Focus or hover this native button to grow its preview from the top-left anchor. The fixed violet point shows which corner remains in place.
<!-- Anchored preview · hover or focus --><div class="p-lg"> <div class="rel h:96px w:160px outline:1px|dashed|var(--color-line-muted)"> <button id="target" type="button" class="grid place-items:center h:96px w:160px p-sm b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 transform:scale(.8) transform-origin:top|left outline:2px|solid|var(--color-blue):focus-visible outline-offset:3px:focus-visible transform:none@print transition:transform|var(--duration-fast)|ease-out@motion transform:scale(1):hover@screen transform:scale(1):focus-visible@screen"> Preview layer </button> <span aria-hidden="true" class="abs left:-3px top:-3px width:6px height:6px r:100% bg-violet-60 untouchable"></span> </div></div>Choose an origin that explains the relationship to the trigger. This example teaches the scale geometry on a real button; an actual menu also needs its own focus and dismissal behavior. Reduced motion removes the animated interpolation.
Apply conditionally
Widen to sm to move the pivot from the center to the top-right corner. The scale stays at 75%, making the origin change visible.
<!-- Center → top right at sm --><div class="p-lg"> <div class="rel h:96px w:160px outline:1px|dashed|var(--color-line-muted)"> <div id="target" class="grid place-items:center h:96px w:160px p-sm b:1px|solid|var(--color-blue-60) r-sm font-sm bg-blue-10 fg-blue-80 transform:scale(.75) transform-origin:center transform-origin:center@print transform-origin:top|right@screen@sm"> Same scale </div> </div></div>The live origin values come from the real viewport query. Print restores the center origin while preserving the scale.