ScreenshotNeo

BlogHow-to

How to Use Multiple CSS Transforms

Combine translate, rotate, scale, and other CSS transform functions in one declaration. Learn how order, transform-origin, and separate transform properties affect the result.

By the ScreenshotNeo team4 October 20266 min read

Put multiple transform functions in one space-separated transform value. For example, transform: translateX(10px) rotate(10deg) scale(1.1) combines translation, rotation, and scaling on the same element. The order matters: rearranging the functions can change the final position and orientation.

1. Combine functions in one transform declaration

The transform property accepts a list of transform functions. Separate functions with spaces, not commas. You can combine 2D and 3D functions as needed.

.card {
  transform: translateX(10px) rotate(10deg) scale(1.1);
}

.panel {
  transform: translate(12px, -6px) skewX(4deg) rotate(2deg);
}

.scene {
  transform: perspective(800px) rotateY(12deg) translateZ(20px);
}

The whole list is one property value. A later transform declaration in the cascade replaces that value, so put the complete desired list in the winning rule. For example, if a hover rule needs to retain a base rotation, include that rotation in the hover list too, or use the separate transform properties described below.

2. Function order changes the result

Each function participates in a composed transformation. The resulting coordinate space affects how subsequent functions act, so the same functions in a different sequence can move an element in a different direction. The W3C specification describes the final transformation as the product of the matrices for the functions in the list. [W3C CSS Transforms]

.first {
  transform: translateX(100px) rotate(30deg);
}

.second {
  transform: rotate(30deg) translateX(100px);
}

These values contain the same operations, but they need not place the elements in the same final position. Try the order that matches the intended motion on the actual element; do not assume the sequence is interchangeable.

3. Build a restrained hover effect

A typical hover combines a small translation, rotation, and scale. The transition animates changes to the complete transform value:

.card {
  transition: transform 180ms ease;
}

.card:hover {
  transform: translateY(-4px) rotate(1deg) scale(1.02);
}

Provide a reduced-motion path when an effect moves or scales content. Scaling and zooming motion can be uncomfortable for some people, so honor the user’s operating-system preference and keep the content understandable without animation. [MDN accessibility guidance]

@media (prefers-reduced-motion: reduce) {
  .card {
    transition: none;
  }

  .card:hover {
    transform: none;
  }
}

4. Choose between a transform list and individual properties

Use transform when you need an explicitly ordered list or functions such as skewX() and perspective(). The individual translate, rotate, and scale properties are useful when components are declared or changed independently, but their composition order is fixed: translate, then rotate, then scale, followed by the transform property. The order in which those CSS declarations appear does not change that composition order. There is no individual skew property. [W3C individual transform properties]

Need Use
Control the sequence of several functions transform: translate(...) rotate(...) scale(...)
Declare movement, rotation, and scale independently translate, rotate, and scale
Skew, perspective, or another transform function transform
Combine independent components with an ordered extra effect Individual properties plus transform, remembering the fixed composition order
.badge {
  translate: 0 -4px;
  rotate: 1deg;
  scale: 1.02;
  transform: skewX(2deg);
}

This is not equivalent to arbitrarily rearranging all four operations into one transform list. Choose the syntax based on whether you need independently controlled components or a specific function order.

5. Set the pivot with transform-origin

Rotation and scaling use a transform origin. Its initial value is the center, 50% 50%. If an element seems to swing around the wrong point, set the origin explicitly:

.door {
  transform-origin: left center;
  transform: rotateY(25deg);
}

.pinwheel {
  transform-origin: 20% 80%;
  transform: rotate(45deg) scale(1.1);
}

The origin changes where the transformation is anchored; it does not change the order of the functions. [MDN transform-origin reference]

6. Account for layout and stacking effects

  • A transform changes visual rendering, but it does not rearrange normal document flow. Other content keeps its original layout space, so transformed elements can overlap neighbors.
  • A non-none transform creates a stacking context. If the element layers unexpectedly, inspect its stacking context and the stacking contexts of nearby elements.
  • A transformed element becomes a containing block for positioned descendants. A position: fixed child inside it may be positioned relative to the transformed ancestor rather than the viewport.
  • Transforms apply only to transformable boxes. If nothing happens, check whether the target is a non-replaced inline element or a table-column box, which are among the exceptions, and check whether another cascade rule wins.

See MDN’s transform reference and the W3C rendering model for the detailed behavior.

7. Debug a transform that looks wrong

  1. Confirm the winning declaration. Inspect computed styles and verify that the active rule contains the whole function list. Another rule may replace the value.
  2. Check spacing and syntax. Write functions as a space-separated list, such as translateX(10px) rotate(10deg); do not use commas between functions.
  3. Change one thing at a time. Temporarily remove functions, then add them back in the intended sequence to identify which operation changes the result.
  4. Inspect the origin. Set transform-origin to a known point such as center or left center to diagnose an unexpected pivot.
  5. Check layout and containing blocks. Overlap may be expected because transforms do not move neighboring layout boxes. Fixed or absolutely positioned descendants may use a transformed ancestor as their containing block.
  6. Check transformability. Some inline and table-related boxes do not accept transforms as expected. Apply the transform to a transformable box, such as an inline-block, when appropriate.

8. Screenshot transformed pages for review

For a visual regression, bug report, or before-and-after review, capture the page at a consistent viewport and state. A browser screenshot can help reveal clipping, overlap, unexpected stacking, and differences between transform orders. Keep the page content and capture settings consistent when comparing images.

Or skip the browser setup

For a rendered screenshot, make one GET request to ScreenshotNeo, a website screenshot API and MCP server by Yorker Media. It returns an image or PDF; see the API documentation.

curl -G "https://api.screenshotneo.com/v1/shot" \
  -d access_key=YOUR_API_KEY \
  --data-urlencode url=https://stripe.com \
  -o shot.webp
import requests

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', new Uint8Array(await res.arrayBuffer()));

Replace YOUR_API_KEY with your key and the example URL with the page you want. The JavaScript example uses Bun’s Bun.write to save the returned bytes; in Node.js, use writeFile from node:fs/promises instead.

ScreenshotNeo removes known cookie and consent banners, newsletter popups, and chat widgets before capture; each cleanup step can be turned off. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and response headers indicate the page verdict and billing status. Its MCP server provides take_screenshot, get_page_info, and capture_pdf for AI agents. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000 shots. Sign up for 1,000 free screenshots a month, no card required.

9. FAQ

Can I put commas between transform functions?

No. Separate functions in one transform list with spaces. Commas may appear inside a function’s arguments, such as translate(10px, 5px).

Does the last transform function replace the earlier ones?

No. The value is a composed list of functions. The order affects the resulting transformation.

Can I animate only one function in a transform list?

A single transform declaration is one property value. For independently controlled components, consider the individual translate, rotate, and scale properties, keeping their fixed composition order in mind.

Why does a transformed child behave differently when fixed?

A transformed ancestor establishes a containing block for positioned descendants, which can change the reference frame used by a fixed-position child.