← 返回首页

简单记一记如何解决切换主题时的明暗闪烁

对于一个明暗双主题的 Astro 主题,在切换页面时经常会出现这样的情况。 这玩意的学名叫做 FOUC ,也叫做 Fla……

前端, Astro

对于一个明暗双主题的 Astro 主题,在切换页面时经常会出现这样的情况。

上图中在切换页面时会出现闪烁问题
上图中在切换页面时会出现闪烁问题

这玩意的学名叫做 FOUC,也叫做 Flash of White。原因是浏览器在加载页面时,会先渲染 HTML。如果此时 JavaScript 还没来得及运行并给 html 标签加上 dark 类名,或者 CSS 还没加载完,浏览器就会默认使用白色背景,导致在暗色模式下看到一瞬间的白屏。

因为我的主题 Haku 也有这样的问题,那就来解决一下。

这是主题 global.css 中的部分代码。

@import url("https://fonts.loli.net/css2?family=Noto+Sans+SC:[email protected]");
@import url("https://fonts.loli.net/css2?family=SN+Pro:ital,wght@0,200..900;1,200..900&display=swap");
@import "tailwindcss";
 
@tailwind utilities;
 
@custom-variant dark (&:where(.dark, .dark *));
 
@layer base {
  :root {
    --haku-font: "SN Pro", "Noto Sans SC", sans-serif;
    --color-border: #a8a8a8;
    --color-readme: #44403b;
    --color-readme-anchor: #155dfc;
    --color-tag: #0a0a0a;
    --color-tag-bg: #dfdfdf;
    --color-tag-bg-hover: #a8a8a8;
    --color-tag-title: #0a0a0a;
    --color-tag-text: #202020;
 
    font-family: var(--haku-font);
    overflow-y: scroll;
  }
 
  html.dark {
    --color-readme-anchor: #2b7fff;
    --color-border: #3a3a3a;
    --color-readme: #d6d3d1;
    --color-tag: #dbdbdb;
    --color-tag-bg: #2b2b2b;
    --color-tag-bg-hover: #666666;
    --color-tag-title: #d5d5d6;
    --color-tag-text: #c5c5c5;
  }
}

首先要去掉 @import 指令,把它放在 <head> 标签中。因为外部 CSS 的优先级比较低,把 CDN 提供的 CSS 放在 HTML 文件里加载更好。

<head>
    <!-- 一些内容 -->
    <link
        rel="stylesheet"
        href="https://fonts.loli.net/css2?family=Noto+Sans+SC:[email protected]"
    />
    <link
        rel="stylesheet"
        href="https://fonts.loli.net/css2?family=SN+Pro:ital,wght@0,200..900;1,200..900&display=swap"
    />
</head>

然后要定义加载时的默认背景色,这就用 color-scheme 和 CSS 变量实现。

:root {
    color-scheme: light;
    background-color: var(--color-bg);
}
 
html.dark {
    color-scheme: dark;
    background-color: var(--color-bg);
}

--color-bg 自己看着,调成背景色就行。

最后,也是最重要的,加一个 JS 阻塞脚本。在 <head> 标签里加一个脚本,从本地配置里面找有没有 theme 一项。

  <script is:inline>
    (function () {
      const theme = localStorage.getItem("theme");
      const systemDark = window.matchMedia(
        "(prefers-color-scheme: dark)",
      ).matches;
      if (theme === "dark" || (!theme && systemDark)) {
        document.documentElement.classList.add("dark");
      } else {
        document.documentElement.classList.remove("dark");
      }
    })();
  </script>

这样就能根据读者本地环境自动适配,能够避免打开网页的时候被白光闪一下。

这个问题已经在两个 PR 里解决了:#50 还有 #49

评论

支持两套评论系统,按需切换加载。