Free · Fast · Privacy-first

CSS Rotate Transform

The CSS rotate() function turns an element clockwise by a specified angle.

Supports deg, rad, and turn angle units

🔒

Includes rotateX, rotateY, rotateZ for 3D rotation

Visual transform-origin control with live pivot preview

Negative value support for counter-clockwise rotation

Cost
Free forever
Sign-up
Not required
Processing
In your browser
Privacy
Files stay local
FreeNo signupWhite-label

Add this Transform Gen to your website

Drop the Transform Gen into any page — blog post, product docs, intranet, school portal — with a single line of HTML. Your visitors get the full tool, processed entirely in their browser. No backend, no uploads, no signup.

  • Files stay 100% in the visitor's browser
  • Responsive — adapts to any container width
  • Free forever, no API key needed

Embed code

<iframe
  src="https://www.fixtools.io/css-tool/transform-gen?embed=1"
  width="100%"
  height="780"
  frameborder="0"
  style="border:0;border-radius:16px;max-width:900px;"
  title="Transform Gen by FixTools"
  loading="lazy"
  allow="clipboard-write"
></iframe>

Attribution-friendly: a small "Powered by FixTools" link appears in the embed footer.

CSS Rotation Units, 3D Axes, and the Role of transform-origin

CSS accepts three angle units for rotation. Degrees are the most familiar: a full rotation is 360deg, a quarter turn is 90deg, and a negative value like rotate(-45deg) rotates counter-clockwise. Radians use the mathematical constant pi: a full rotation is 6.283rad, a right angle is 1.571rad. Turns express the rotation as a fraction of a full circle: 0.25turn is a quarter rotation, 1turn is a full rotation, and 2.5turn spins the element two and a half times. All three units are equivalent and interchangeable in any browser that supports the transform property. Degrees are easiest to reason about for most UI work, while turns are more expressive for spinner animations where the number of full rotations matters.

The 3D rotation functions rotate an element around a specific axis in three-dimensional space. rotateX(angle) tilts the element toward or away from the viewer along the horizontal axis, like flipping a page backward. rotateY(angle) spins the element around the vertical axis, like turning a book to show its spine. rotateZ(angle) is identical to the 2D rotate() function: it rotates around the axis pointing out of the screen toward the viewer. For 3D rotation to produce a visible depth effect, a perspective value must be set either as a perspective() function in the transform list or as the perspective property on the parent element. Without perspective, rotateX and rotateY produce a flat-looking compression rather than true depth.

The transform-origin property defines the point around which the transform is applied. Its default value is 50% 50%, the center of the element. Changing it to 0% 0% moves the pivot to the top-left corner; top right sets it to 0% 0% on the horizontal axis and 100% on the vertical. For a clock hand that should rotate from its base, set transform-origin: bottom center. For a door hinge effect, set transform-origin: left center. The origin can be set in pixels, percentages, or keyword values like top, bottom, left, right, and center. The generator exposes origin as a clickable grid so you can see exactly where the pivot sits on the element before copying the CSS.

Rotation behaves inconsistently across engines when subpixel positioning interacts with rotation angles that are not multiples of 90 degrees. Safari on macOS and iOS rasterizes the rotated element to a texture and uses high-quality bilinear filtering, which can introduce a slight blur on text below 14 pixels. Firefox uses a similar approach but with sharper edges, while Chromium engines apply transform smoothing that varies with the GPU driver. To minimize cross-browser drift, round angle values to whole degrees, avoid rotating elements containing small text, and apply transform: translateZ(0) to force a stable rasterization plane. For icons and decorative graphics the differences are imperceptible, but for body copy or numerical displays you should test in all three engines before shipping.

How to use this tool

💡

Select the rotate function, type an angle value or drag the dial, choose the unit from the dropdown, and adjust transform-origin using the grid control. For 3D rotation, add a perspective value to the parent container field. Copy the finished CSS when the preview matches your intent.

How It Works

Step-by-step guide to css rotate transform:

  1. 1

    Choose the rotation axis

    Select rotate() for 2D, or rotateX(), rotateY(), or rotateZ() for 3D. For 3D functions, enter a perspective value in the parent container field to make the depth visible.

  2. 2

    Set the angle and unit

    Type an angle value or drag the rotation dial. Choose deg, rad, or turn from the unit dropdown. The preview updates in real time as you adjust.

  3. 3

    Adjust transform-origin

    Click a point on the origin grid or type custom values to move the pivot point. Watch the preview to confirm the element rotates around the intended axis.

  4. 4

    Copy the CSS output

    Click Copy Code to copy the transform declaration and, if applicable, the transform-origin property. Paste both into your stylesheet selector.

Real-world examples

Common situations where this approach makes a real difference:

Animated hamburger menu icon

A front-end developer builds a hamburger icon that transforms into an X on click. The top bar rotates rotate(45deg), the middle bar fades out with opacity: 0, and the bottom bar rotates rotate(-45deg). The generator is used to confirm the angle values and the correct transform-origin for each bar so the rotation produces a clean X shape. The CSS is copied into a toggled class that JavaScript applies on button click.

Vertical sidebar navigation label

A dashboard UI has a collapsible sidebar with section labels that display vertically when collapsed. The developer uses the generator to apply rotate(-90deg) with transform-origin: center center to the label text. The preview confirms the text reads bottom-to-top, which is the standard reading direction for vertical labels in Western layouts. The generated CSS is placed in a collapsed state class.

Loading spinner with CSS animation

A spinner component needs to rotate continuously. The developer uses the generator to set rotate(1turn) as the 100% keyframe value, confirms the pivot is at the center, and copies the transform value into a @keyframes block with animation: spin 800ms linear infinite. The turn unit makes the one-full-rotation intent explicit in the keyframe definition.

3D product card tilt on hover

An e-commerce site wants product cards to tilt slightly in 3D on hover, giving a tactile feel. The developer uses the generator to combine rotateX(8deg) and rotateY(-5deg) with a perspective of 600px on the card container. The generator preview confirms the tilt looks natural at those values. The CSS is placed in a :hover selector with transition: transform 150ms ease-out for smooth entry and exit.

Pro tips

Get better results with these expert suggestions:

1

Use CSS custom properties to make rotation configurable

Declaring --rotate-angle: 45deg on a root or component element and using transform: rotate(var(--rotate-angle)) makes it trivial to change the rotation from JavaScript or a Tailwind arbitrary value without touching the CSS rule itself. This pattern is particularly useful for icon components where the rotation angle communicates state, such as a chevron that points down at 0deg and up at 180deg.

2

Prefer the standalone rotate property for single-axis rotation

CSS now supports a standalone rotate property separate from transform. Writing rotate: 45deg is equivalent to transform: rotate(45deg) but does not interfere with other transform functions applied to the same element via a different rule or animation. This is useful in component libraries where a base style applies a transform and a variant needs to add rotation without overriding the base.

3

Test rotateX and rotateY at 89deg to check perspective depth

Setting rotateX or rotateY to 89 degrees pushes the element nearly perpendicular to the viewer. If the element appears as a thin line rather than a tilted plane, the perspective value on the parent is missing or too large. A perspective of 400px to 800px produces visible depth for most element sizes. Adjust the perspective value until elements rotated to 60 to 80 degrees look convincingly three-dimensional.

4

Avoid rotating text elements more than 90 degrees without testing readability

Rotated text beyond 90 degrees becomes upside-down or mirrored and is generally unreadable. Sidebar labels rotated 90 degrees counterclockwise with rotate(-90deg) are common and readable, but 270-degree rotation achieves the same visual result and may render more consistently across browsers for elements with complex backgrounds or gradients.

5

Use turn units for spinner animations

For a loading spinner that rotates indefinitely, writing rotate(1turn) in the 100% keyframe is clearer than rotate(360deg). The browser treats them identically, but turn makes the intent readable: the spinner completes exactly one full rotation per animation cycle, regardless of any easing applied.

6

Set transform-origin before writing rotation values

Changing transform-origin after deciding on an angle value often makes the visual result look wrong. Lock the pivot point first, then adjust the angle. This is especially important for elements that should appear to hinge, fold, or orbit around a specific edge or corner rather than their center.

7

Combine rotateY with backface-visibility for card flips

A card flip requires rotateY(180deg) on the card container, backface-visibility: hidden on both the front and back faces, and transform-style: preserve-3d on the container. Setting backface-visibility: hidden prevents the back of the front face from showing through when the card is face-down.

FAQ

Frequently asked questions

CSS rotate() accepts deg for degrees, rad for radians, turn for full rotations, and grad for gradians. Degrees are the most common in practice: 360deg is a full rotation. Radians are used when working with mathematical calculations: a full rotation is approximately 6.2832rad. Turns express rotation as a fraction of a circle, so 0.5turn is a half rotation and 2turn is two full rotations. All units produce identical results; the choice is about readability in your codebase.
Set transform-origin to the corner you want to use as the pivot. For the top-left corner, use transform-origin: 0 0 or transform-origin: top left. For the bottom-right corner, use transform-origin: 100% 100% or transform-origin: bottom right. After setting the origin, apply the rotate() value. The element rotates around the specified corner. You can also use pixel values relative to the element if the corner is not at the edge, for example transform-origin: 20px 20px.
They are functionally identical. rotate(45deg) and rotateZ(45deg) both rotate the element clockwise by 45 degrees around the axis perpendicular to the screen. rotateZ() is the explicit 3D form of the same operation. In a 3D transform context where transform-style: preserve-3d is active, using rotateZ() is more explicit about which axis you are rotating around. For 2D rotation, rotate() is shorter and more conventional.
Without a perspective value, the browser projects 3D coordinates onto the 2D screen using an orthographic projection, meaning all depth information is lost. A 90-degree rotateY on an element with no perspective simply collapses it to a vertical line because every point at different Z depths maps to the same 2D position. Adding perspective: 600px to the parent, or perspective(600px) inside the transform list, switches to a perspective projection where closer points appear larger, creating the illusion of depth.
Yes, but SVG elements use a different default coordinate system. The transform-origin for SVG elements defaults to 0 0 in older browsers instead of 50% 50%, so a rotation that looks centered in HTML may pivot from the top-left corner on an SVG element. Modern browsers align SVG transform-origin behavior with HTML when using CSS transforms. To be safe, explicitly set transform-origin on SVG elements you want to rotate, and test in Firefox and Safari as well as Chrome.
Yes. A rotated element's pointer event hit area follows the rotated bounding box. If you rotate a button 45 degrees, the clickable area is the rotated diamond shape, not the original rectangle. This is different from how overflow or visual clipping works. If you need the hit area to remain a rectangle aligned with the viewport, you may need to use a transparent overlay element at the original position to capture the click event while the visual element is rotated.
Define a @keyframes rule with transform: rotate(0deg) at 0% and transform: rotate(360deg) at 100%, then apply animation: your-name duration linear infinite to the element. Using linear timing ensures constant speed throughout the rotation. Using turn units makes the intent clearer: rotate(0turn) at 0% and rotate(1turn) at 100% explicitly states that each cycle completes one full rotation. Avoid ease or ease-in-out for continuous spinners as they create visible acceleration and deceleration each loop.
The standalone rotate property, added in CSS Transforms Level 2, is composited independently from the transform property. This means you can set transform: translateX(100px) on an element and also set rotate: 45deg without either overriding the other. In contrast, using transform: rotate(45deg) on an element that already has transform: translateX(100px) in another rule will override the translate unless you include both functions in the same transform declaration. The standalone rotate property is supported in all modern browsers as of 2022.
Wrap your rotation animation in @media (prefers-reduced-motion: no-preference) so the animation only runs for users who have not opted out. For users who have, either remove the animation entirely or replace the spin with a static end state that communicates the same information. Continuous rotation is especially disorienting for users with vestibular disorders, so a loading spinner using rotate() should fall back to an opacity pulse or a static label that reads Loading. The media query is read once on page load and again whenever the operating system setting changes, so you do not need any JavaScript to detect or respond to the preference.
A rotated element creates a new stacking context. Inside that context, z-index values on descendants are compared only against each other, not against elements outside the rotated ancestor. A child with z-index: 9999 inside a rotated card will still render below an unrelated sibling element outside the card if the card itself has a lower stacking position. The fix is to lift the rotated container into a higher position in its own context, or to flatten the markup so the element you want on top is a sibling of the rotated container rather than a descendant. The standalone rotate property creates the same stacking context as transform. The same rule applies to position: fixed children: once an ancestor is rotated, fixed positioning is calculated against the rotated container rather than the viewport, which often surprises developers building dropdowns or tooltips nested inside a rotated card layout that previously worked outside it.

Related guides

More use-case guides for the same tool:

Ready to get started?

Open the full Transform Gen — free, no account needed, works on any device.

Open Transform Gen →

Free · No account needed · Works on any device