fix(theme): 用整页快照过渡消除明暗割裂

- 支持 View Transition 时整页旧/新快照交叉淡入 160ms,背景图与底色不再各自过渡
- 不支持或减少动画偏好时回退到原来的颜色过渡
This commit is contained in:
2026-11-03 20:30:05 +08:00
parent 5439ebf3be
commit a5d7859c6e
2 changed files with 33 additions and 1 deletions
+14
View File
@@ -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;
}
}
+19 -1
View File
@@ -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)