From a5d7859c6e1758a1e32cdb8f687c7658e0a173d7 Mon Sep 17 00:00:00 2001 From: CNWei Date: Tue, 3 Nov 2026 20:30:05 +0800 Subject: [PATCH] =?UTF-8?q?fix(theme):=20=E7=94=A8=E6=95=B4=E9=A1=B5?= =?UTF-8?q?=E5=BF=AB=E7=85=A7=E8=BF=87=E6=B8=A1=E6=B6=88=E9=99=A4=E6=98=8E?= =?UTF-8?q?=E6=9A=97=E5=89=B2=E8=A3=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 支持 View Transition 时整页旧/新快照交叉淡入 160ms,背景图与底色不再各自过渡 - 不支持或减少动画偏好时回退到原来的颜色过渡 --- stash-web/src/App.css | 14 ++++++++++++++ stash-web/src/AppNext.tsx | 20 +++++++++++++++++++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/stash-web/src/App.css b/stash-web/src/App.css index 55ab461..c5ed1ff 100644 --- a/stash-web/src/App.css +++ b/stash-web/src/App.css @@ -1422,3 +1422,17 @@ html.theme-transition .site-background { grid-template-columns: minmax(0, 1fr); } } + +/* 明暗切换:支持的浏览器直接对整页做快照交叉淡入,避免背景图和底色各变各的 */ +::view-transition-old(root), +::view-transition-new(root) { + animation-duration: 160ms; + animation-timing-function: var(--su-ease-in-out); +} + +@media (prefers-reduced-motion: reduce) { + ::view-transition-old(root), + ::view-transition-new(root) { + animation: none; + } +} diff --git a/stash-web/src/AppNext.tsx b/stash-web/src/AppNext.tsx index bb3fc4c..74d27c5 100644 --- a/stash-web/src/AppNext.tsx +++ b/stash-web/src/AppNext.tsx @@ -308,8 +308,26 @@ export default function AppNext() { useEffect(() => { const root = document.documentElement if (root.dataset.scheme === scheme) return + + const apply = () => { + root.dataset.scheme = scheme + } + const doc = document as Document & { + startViewTransition?: (callback: () => void) => unknown + } + const reduceMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches + + if (!reduceMotion && typeof doc.startViewTransition === 'function') { + try { + doc.startViewTransition(apply) + return + } catch { + // 浏览器正在跑另一段过渡时退回 CSS 过渡 + } + } + root.classList.add('theme-transition') - root.dataset.scheme = scheme + apply() const timer = window.setTimeout(() => root.classList.remove('theme-transition'), 180) return () => { window.clearTimeout(timer)