Why Isn't My 3D View Transition Working? | CSS-Tricks
#Frontend

Why Isn't My 3D View Transition Working? | CSS-Tricks

Frontend Reporter
2 min read

Explains why 3D cross-document view transitions fail and provides a solution using perspective() inside keyframes.

A 3D flip between pages feels natural, yet browsers often flatten the effect.

When you try to animate a cross‑document view transition with a 3D feel, the first hurdle is the perspective property. In a simple card flip the parent container holds the perspective and the child receives the transform. In a view transition the browser builds a shadow tree of old and new snapshots, and that tree does not behave like ordinary DOM nodes.

Featured image

The snapshot tree is rendered above the regular page, and the browser overrides many of the usual styling hooks. Trying to place perspective on , on :root, or inside ::view‑transition‑old or ::view‑transition‑new does nothing because those selectors are not treated as real parents. The only way to give the animation a 3D space is to use the perspective() function inside the keyframes themselves.

@keyframes flip-out { 0% { transform: perspective(1100px) rotateY(0deg); opacity: 1; } 100% { transform: perspective(1100px) rotateY(-90deg); opacity: 0; } } @keyframes flip-in { 0% { transform: perspective(1100px) rotateY(90deg); opacity: 0; } 100% { transform: perspective(1100px) rotateY(0deg); opacity: 1; } }

The perspective() function works because it is applied directly to the element that receives the animation, not to a parent that the browser may replace. By embedding the perspective value in the transform, the effect survives the view‑transition layer.

Here is a minimal example that you can copy into a page that opts into view transitions:

@view-transition { navigation: auto; } @keyframes flip-out { … } @keyframes flip-in { … } ::view-transition-old(root) { animation: flip-out 0.3s cubic-bezier(0.4,0,0.2,1) forwards; transform-origin: center center; } ::view-transition-new(root) { animation: flip-in 0.3s cubic-bezier(0,0,0.6,1) 0.3s backwards; transform-origin: center center; }

For more details on the view‑transition spec see the MDN page https://developer.mozilla.org/en-US/docs/Web/CSS/@view-transition and the CSS perspective documentation https://developer.mozilla.org/en-US/docs/Web/CSS/perspective. Bramus explored the same issue in a recent post https://bramus.github.io/2023/05/08/view-transitions-and-3d/.

The key takeaway is that perspective must live inside the animation, not on a parent selector. Once you make that shift the 3D flip works across navigations just like it does on a single page.

Comments

Loading comments...