【Astro】修正深色模式閃爍 View Transitions
我在換頁時看到短暫的主題閃爍,按下 F5 重新整理時更明顯。這篇文章記錄修正方式與取捨。
問題 #
這個網站使用 Astro 的 view transitions 並有主題切換功能,換頁時,新文件可能在主題 class 重新套用前就先繪製。硬重新整理時,HTML 比 JavaScript 先到,瀏覽器會先畫出預設主題。
且一開始有使用 <ClientRouter /> 寫在 <head /> 也有在我的 Layout 組件上新增 astro:after-swap 監聽器(根據 Astro 官方文檔 描述的去做)
改動 #
嘗試把 <ClientRouter /> 寫在 src/layouts/BaseLayout.astro 加上 client router,並用一段 inline script 在交換前後同步主題:
import { ClientRouter } from "astro:transitions";
<!-- 省略 -->
<html lang="en">
<head>
<script is:inline>
document.documentElement.style.visibility = "hidden";
const applyTheme = () => {
const isDark = getThemePreference() === "dark";
document.documentElement.classList.toggle("dark", isDark);
document.documentElement.style.colorScheme = isDark ? "dark" : "light";
document.documentElement.style.visibility = "";
};
applyTheme();
document.addEventListener("astro:before-swap", (event) => {
const nextDocument = event.newDocument;
const isDark = document.documentElement.classList.contains("dark");
nextDocument.documentElement.classList.toggle("dark", isDark);
nextDocument.documentElement.style.colorScheme = isDark ? "dark" : "light";
});
document.addEventListener("astro:after-swap", applyTheme);
</script>
<ClientRouter />
</head>
<!-- 省略 -->
</html>
某些固定 UI 組件可以加上 transition:persist 避免在轉場的移除又載入 UI(Maintain State 維持狀態)。
<Header
client:load
pathname={pathname}
transition:persist
transition:name="Header"
/>
備註 #
這樣可以降低硬重新整理的閃爍,但在純靜態站點無法完全保證首屏零閃。若要真正零閃,需要改成 SSR,並用 theme cookie 讓伺服器直接渲染正確的 class。