From bf6477f16155c4141451df152628b63748d6086f Mon Sep 17 00:00:00 2001 From: Lorenzo Corallo Date: Thu, 15 Oct 2026 12:23:36 +0200 Subject: [PATCH] fix(theme): place the reveal circle in percentages so it stays on the toggle when zoomed With browser zoom, Chrome scales px lengths on the view-transition pseudo-elements again, so the circle's center drifted away from the toggle toward the middle of the screen. The center and radius are now percentages of the snapshot box, which zoom cannot distort. --- src/components/shell/theme.ts | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/components/shell/theme.ts b/src/components/shell/theme.ts index 7efc4932..ca4c1fb5 100644 --- a/src/components/shell/theme.ts +++ b/src/components/shell/theme.ts @@ -213,10 +213,16 @@ function switchTheme(theme: Theme, source?: ThemeToggleSource) { const current: Reveal = { from, to: theme, heading: theme, clip: null, hold: null } reveal = current const toggle = revealToggle(source) - const { x, y } = iconCenter(toggle) ?? { x: window.innerWidth / 2, y: window.innerHeight / 2 } - const radius = Math.hypot(Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y)) + const width = window.innerWidth + const height = window.innerHeight + const { x, y } = iconCenter(toggle) ?? { x: width / 2, y: height / 2 } + const radius = Math.hypot(Math.max(x, width - x), Math.max(y, height - y)) const lightOn = theme === "light" - const bulb = (r: number) => `circle(${r}px at ${x}px ${y}px)` + // In percentages of the snapshot (the viewport), not px: under browser zoom Chrome scales px lengths on the + // transition pseudo-elements a second time, which moved the circle off the toggle. A circle's % radius is + // relative to the box's diagonal / √2. + const bulb = (r: number) => + `circle(${(r / (Math.hypot(width, height) / Math.SQRT2)) * 100}% at ${(x / width) * 100}% ${(y / height) * 100}%)` // The new snapshot is live: keep CSS transitions off until the reveal ends, or colors would also fade. root.setAttribute("data-theme-switching", "") root.setAttribute("data-theme-reveal", lightOn ? "on" : "off")