Remove white flash during view transitions #3026
Service Desk opened 5 days ago

Motivation

After enabling cross-document view transitions on layout pages, full-page navigations flash white. The flash is most obvious in dark mode. Sidebar and topbar stay on screen (they have their own view-transition-names), but they still use the browser default cross-fade, so the same white color punches through those snapshots too.

This is a UX regression of the chrome-pinning work. The goal is to keep that design (named .sidebar / .topbar, no extra HTML ids, no Wicket markup ids) and stop the white midpoint without breaking the always-dark sidebar in light mode.

Why it flashes

The browser default root animation fades ::view-transition-old(root) out while ::view-transition-new(root) fades in. At the midpoint both snapshots are translucent, so whatever sits behind the ::view-transition overlay shows through.

That backing surface is the browsing-context canvas, not the live html / body background. We do not set color-scheme on html, so the canvas stays the UA default (typically white). Page backgrounds are already themed (#EEF0F8 in light mode, var(--dark-mode-darker) / #151521 in dark mode), but they are not what you see through the overlay.

.sidebar and .topbar are separate named snapshots so they do not blank with the document. They still get the same default fade (including mix-blend-mode: plus-lighter on the image pair) unless those groups are given their own opaque backgrounds.

Approaches that do not work

These were considered and rejected. Do not implement them.

  1. Name body. html is already the automatic root participant. body is in that root snapshot. Page content still lives in body, so a body name would still cross-fade and would fight the “only pin chrome” design. It can also stack awkwardly with the automatic root name on html.

  2. Make the canvas / ::view-transition transparent. ::view-transition is already transparent. That is why the white canvas shows through. Transparency does not treat light and dark mode the same: light mode is already near-white so the flash is easy to miss; dark mode still shows white through #151521.

  3. Set color-scheme on html. That only picks one browsing-context canvas color. .sidebar is always var(--dark-mode-dark) (#23232d), including in light mode. A light canvas would make the sidebar fade flash white. A dark canvas would fix dark mode and the sidebar, but would be wrong for the light-mode page and topbar. One canvas color cannot be both the page theme and the always-dark sidebar.

  4. Name .sidebar descendants and .side-info for a smoother morph. Cross-document view transitions require a unique view-transition-name in each document. A duplicate name skips the whole transition.

    • Menu classes (.sidebar-menu, .menu-header, .menu-item, .menu-link) are repeated (user/admin menu plus project menu; many items). Labels are not unique either (Code exists as both a top-level submenu and a Settings submenu). Unique names would need a stable per-item key in markup, which this work must not add.
    • .sidebar-body is unique but large, and its contents change, so naming it adds a snapshot without much extra smoothness.
    • a.side-info is duplicated on issue/PR/build pages (header trigger + dock). div.side-info is usually one panel, but on desktop it is in-flow (not position: fixed), it is fixed only below 1199px / .hide-side-info, many layout pages have no panel, and its children (.header, .body) are generic and page-specific so they almost never pair.

    Unique always-present sidebar chrome (.sidebar-header, .sidebar-brand, .sidebar-footer) could be named later as a separate, carefully scoped change. It is out of scope here.

Design

Stop relying on the canvas. Treat each snapshot group as its own surface, and keep the chrome fade.

  1. Paint the overlay / root group with the page background: #EEF0F8 in light mode, var(--dark-mode-darker) in dark mode. Root still cross-fades, but the midpoint is the theme color instead of white.

  2. Keep the default fade on .sidebar and .topbar (chrome fade is wanted). Give each group an opaque background so the fade never punches through to the canvas:

    • ::view-transition-group(sidebar): var(--dark-mode-dark) in both themes (matches .sidebar).
    • ::view-transition-group(topbar): white in light mode, var(--dark-mode-dark) in dark mode (matches .topbar).
  3. Do not set color-scheme on html. Do not add view-transition-name on body, .side-info, .main, or sidebar descendants.

Existing constraints still apply: @view-transition { navigation: auto; }, honor prefers-reduced-motion: reduce, no extra HTML ids, no Wicket markup ids, unsupported browsers unchanged.

Acceptance criteria

  •  Same-origin full navigations between LayoutPage screens no longer flash white at the root midpoint in light or dark mode
  •  Sidebar stays dark during the chrome fade in both themes (no light-mode white punch-through)
  •  Topbar fade uses white in light mode and var(--dark-mode-dark) in dark mode
  •  Chrome fade is preserved (do not disable the sidebar/topbar cross-fade)
  •  No color-scheme on html, and no new view-transition-name on body, .side-info, .main, or sidebar descendants
  •  prefers-reduced-motion: reduce still disables the effect
  •  Unsupported browsers are unchanged
1/1
Type
Improvement
Priority
Normal
Assignee
Labels
No labels
Issue Votes (0)
Watchers (2)
Reference
OD-3026
Please wait...
Connection lost or session expired, reload to recover
Page is in error, reload to recover