From 4b781d3c76b0ea0d1b805e55f1cc782e7dfc8446 Mon Sep 17 00:00:00 2001 From: Tyler Date: Wed, 17 Jun 2026 10:40:46 -0600 Subject: [PATCH] Disable named view transition on admin page-content wrapper MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The wrapper around the admin main content was triggering a 'shared element' morph on every page load and navigation: the browser tries to animate the bounding box of the named element across the old and new pages, and since each admin page has a different height, the browser was scaling the snapshot from the top-left corner. That read as the page 'loading from the corner with keyframes' and pushed the bottom of the content to the top during the transition. Setting update="none" opts out of the named transition entirely. The children just swap on navigation — no fade, no scale, no morph. The AdminSidebar + parchment background stay mounted across navigations so the cut reads as a content swap inside a stable shell, which is what the eye expects for a logged-in admin app. The ::view-transition-old(page-content) / ::view-transition-new CSS rules in globals.css are left in place in case we want to re-enable with a different shape later (pure-opacity rules on the root pseudo-elements instead of a named wrapper). --- .../transitions/SmoothViewTransition.tsx | 63 +++++++------------ 1 file changed, 22 insertions(+), 41 deletions(-) diff --git a/src/components/transitions/SmoothViewTransition.tsx b/src/components/transitions/SmoothViewTransition.tsx index fd2fdc8..ddd6cd9 100644 --- a/src/components/transitions/SmoothViewTransition.tsx +++ b/src/components/transitions/SmoothViewTransition.tsx @@ -4,48 +4,29 @@ import { ViewTransition } from "react"; import type { ReactNode } from "react"; /** - * Smooth view-transition wrapper for any page-section content. + * Page-content wrapper. The named `page-content` view transition used + * to apply a CSS-driven crossfade (::view-transition-old/new rules in + * globals.css) on every navigation. The opacity fade itself was fine, + * but because the named transition attaches `view-transition-name: + * page-content` to the wrapper, the browser also tries to morph the + * wrapper's bounding box across pages — and since each admin page has + * a different height, the browser was scaling the snapshot from the + * top-left corner, which read as the page "loading from the corner" + * and pushed the bottom of the content to the top during the + * transition. * - * Drop this around the main content area of a route (or around an - * individual chunk) to opt that subtree into a soft - * crossfade on navigation. The browser's native View Transitions API - * handles the actual animation — when the browser doesn't support it, - * the children just swap, no error. + * `update="none"` opts out of the named transition entirely. The + * children just swap on navigation (no fade, no scale, no morph) — + * the AdminSidebar + parchment background stay mounted across + * navigations so the cut reads as a content swap inside a stable + * shell, which is what the eye expects for a logged-in admin app. * - * `name` groups elements so the browser can morph the same element - * across pages. Use the same name on the source and destination (e.g. - * the page header) for shared-element morphing. Use the default - * `"page-content"` for plain crossfades. - * - * Motion note: the CSS-side ::view-transition-old/new rules are a - * 90/140ms pure-opacity fade with NO translate. Earlier versions - * shifted the page 4-6px on enter/exit which compounded with the route - * content settling into place and read as a small "drop" — bad for - * vestibular comfort. A flat opacity crossfade softens the cut - * without any positional movement. - * - * Usage: - *
- * {children} - *
+ * If we ever want a subtle crossfade back, the right shape is a + * pure-opacity ::view-transition-old/new pair with NO named wrapper + * (i.e. drop the `name` prop and add the rules to + * ::view-transition-old(root) / ::view-transition-new(root) so the + * browser doesn't morph the bounding box). */ -export function SmoothViewTransition({ - children, - name = "page-content", -}: { - children: ReactNode; - name?: string; -}) { - return ( - - {children} - - ); +export function SmoothViewTransition({ children }: { children: ReactNode }) { + return {children}; }