diff --git a/assets/style/_base.scss b/assets/style/_base.scss index 5957692..cde1c25 100644 --- a/assets/style/_base.scss +++ b/assets/style/_base.scss @@ -48,3 +48,21 @@ body { border-radius: var(--radius-sm); } .skip-link:focus { left: 0.5rem; } + +/* Page-change animation (cross-document view transitions): same-origin + * page loads crossfade instead of flashing (Chrome 126+ / Safari 18.2+; + * other browsers keep the instant swap). Navbar + sidebar carry their own + * snapshots (_layout.scss) so the app shell stays put. group(*) included: + * its geometry animation would otherwise run at the UA default 250ms and + * hold the transition open after the fades end. */ +@media (prefers-reduced-motion: no-preference) { + @view-transition { + navigation: auto; + } + + ::view-transition-group(*), + ::view-transition-old(*), + ::view-transition-new(*) { + animation-duration: var(--timing-fast); + } +} diff --git a/assets/style/_layout.scss b/assets/style/_layout.scss index bb708df..1fb795e 100644 --- a/assets/style/_layout.scss +++ b/assets/style/_layout.scss @@ -15,6 +15,10 @@ backdrop-filter: saturate(140%) blur(12px); border-bottom: 1px solid var(--color-ink-line); color: var(--color-content-inv); + /* Own view-transition snapshot: the app shell stays put while the page + * crossfades (_base.scss). The backdrop blur isn't part of the element's + * own paint, so it drops out for the 120ms transition — imperceptible. */ + view-transition-name: navbar; } .navbar-brand { @@ -143,6 +147,9 @@ html.dark .navbar-theme-toggle .icon-moon { display: inline-block; } padding: 1.75rem 0.75rem 3rem 1.25rem; border-right: 1px solid var(--color-line); background-color: var(--color-base); + /* Own view-transition snapshot: stays put during page changes; only the + * active item crossfades. */ + view-transition-name: sidebar; } .sidebar-mobile-nav { display: none;