NEW POSTS
latest

CSS transform-style Property

Understanding the CSS transform-style Property

Rotating cards, spinning cubes, and layered scenes all rely on CSS 3D transforms. But applying a 3D transform to an element does not automatically make its nested elements behave like real 3D objects. Whether they do depends on a small property called transform-style. This article explains what it controls, how its two values differ, and why it is behind so many confusing 3D bugs. You can also experiment with everything in the live editor further down the page.



What is the transform-style Property?

Think of a transformed element as a sheet of glass and its children as stickers on that sheet. The transform-style property decides whether the children are treated as stickers that stay on the surface of the glass, or as separate objects that each keep their own depth in front of and behind it.

The sticker behavior is the default. If you rotate a child with rotateY() or push it forward with translateZ(), the browser still applies that transform, but the result is painted onto the parent's surface. The child can never sit in front of, behind, or through other elements in a shared 3D scene. Switching on the 3D behavior removes that limit.

Definition: transform-style is a CSS property that you set on a parent element to tell the browser how to render that element's children when 3D transforms are involved. With preserve-3d, the children keep their own positions in 3D space and share one scene with the parent. With flat, the children are drawn onto the parent's two-dimensional surface and lose their independent depth.

Core Property Values

The property accepts two keywords:

  • flat (Default): Children are drawn onto their parent's surface. Their own transforms still apply, but the parent is first rendered as a single flat picture, and only that picture takes part in the parent's rotation. Because every element starts this way, you rarely need to write transform-style: flat;, except to undo a preserve-3d declared by another rule.
  • preserve-3d: Children share a 3D scene with their parent. Each child keeps its own position and rotation in depth, so siblings can overlap correctly, intersect, or sit in front of and behind each other. Use it on any transformed element whose children must keep their depth, such as a card with two faces or a cube with six.

Note that preserve-3d is not needed to rotate a single element. A lone element can be turned with transform: rotateY(180deg) and no transform-style at all. The property only matters when an element has children that must keep their 3D relationship inside it.


Practical Example: 3D Card Container (Live Editor)

To see how this works in practice, consider a common card-flipping component. The editor below contains the HTML and CSS on the left and a live preview on the right. Hover over the card in the preview to flip it, and edit either code box to see the result instantly. Without preserve-3d on the rotating container, the two faces are flattened onto the container's plane instead of living in 3D space.

HTML Structure (editable)
CSS (editable)
Live Preview (hover to flip)

Things to Try in the Editor

  • Delete the transform-style: preserve-3d; line from .card. The browser falls back to flat, both faces are flattened onto the card's plane, and the back face (already turned 180 degrees) is drawn over the front face, so the flip effect is ruined.
  • Add overflow: hidden; or opacity: 0.9; to .card. This silently forces the used value back to flat and breaks the flip.
  • Remove perspective: 600px; from .scene. The rotation still happens, but it looks flat instead of having depth.
  • Remove backface-visibility: hidden; from .card-face. The face turned away from you now shows through as a mirrored image.

How perspective and transform-style Work Together

These two properties are often confused, but they do different jobs. perspective is set on a parent and gives its direct children a sense of depth: things closer to the viewer look larger. transform-style: preserve-3d keeps the deeper descendants in that same 3D space instead of flattening them. In the example, perspective on .scene creates the viewing distance for .card, and preserve-3d on .card lets the two faces inside it share that 3D space and be drawn with the same perspective. Without perspective, the rotation still happens but looks flat and orthographic; without preserve-3d, the faces collapse into a plane.

Why the Example Needs backface-visibility

The backface-visibility: hidden; rule is not part of transform-style, but the card flip depends on it. When the card turns, the front face ends up facing away from the viewer, and by default a face turned away is still drawn as a mirrored image. Hiding the back side of each face ensures that only the face currently pointing toward the viewer is visible.


Important Usage Considerations for Developers

  • Not Inherited: transform-style is not an inherited property. If you have deep nesting, you must declare transform-style: preserve-3d on every intermediate ancestor that sits between the 3D parent and the 3D content. The 3D chain breaks at the first ancestor that is flat: everything below that element is flattened onto its plane, no matter what its own children declare. This is one of the most common reasons a 3D scene "stops working" after an extra wrapper element is added.
  • Some Properties Force flat: Certain properties require an element to be rendered as a single flattened group, and they force the used value of transform-style back to flat even if you wrote preserve-3d. This behavior is deterministic, not occasional. Common triggers include:
    • overflow set to any value other than visible or clip (for example hidden, auto, or scroll)
    • opacity with a value less than 1
    • filter and backdrop-filter with a value other than none
    • clip with a value other than auto, and clip-path with a value other than none
    • mask properties such as mask-image with a value other than none
    • isolation: isolate
    • mix-blend-mode with a value other than normal
    • contain: paint, and anything that implies it, such as content-visibility: hidden
    For example, adding overflow: hidden or opacity: 0.9 to the .card element in the live editor above would silently flatten it and break the flip. If a 3D effect stops working, check the element and its ancestors for these properties first. To fade or clip a 3D object, apply those properties to a wrapper outside the 3D structure, or to the individual faces, instead of to the element that has preserve-3d.

Conclusion

The transform-style property is small, but it decides whether nested elements behave like real 3D objects or like paint on a flat surface. When a 3D layout misbehaves, check three things in order: is preserve-3d set on every element in the chain, is perspective applied on an ancestor, and does any element in the chain use a property that forces flat?

The transform-style property also supports standard global CSS values such as inherit, initial, revert, revert-layer, and unset.

Further Reading

For the formal definition and browser support details, see the MDN Web Docs page for transform-style.

NEXT »

No comments

US Flag
play button