问题 ¶
我写的这个 Hugo 主题之前一直有个毛病. 它默认是亮色主题,但如果调到暗色主题1,那么加载新页面时网站会先渲染亮色主题,然后再自动切换到暗色主题,观感上就是它闪烁了一下. 我本来以为这是静态网站的通病,直到我看到别人的主题就没这个毛病,比如 PaperMod⧉. 所以这个问题是一定有解决方案的.
我先查了一下,Cupper 主题⧉的维护者写过一篇文章:Fix the White Flash on Page Load When Using a Dark Theme on a Static Site⧉. 我试了 ta 的方案,Chrome 浏览器下此方案确实解决了问题,但是 Firefox 下问题依然存在:Firefox 会把 visibility: hidden; opacity: 0;
渲染成白色,等 DOMContentLoaded
事件发生后,showContent()
函数再把内容展示出来,也就是说它还是会闪烁,只不过之前是闪一下亮色主题,现在是闪一下纯白页,实际观感同样糟糕.
Firefox 与 Chrome 的差异我觉得更像是 Chrome 的开发者使用了魔法,来帮助其用户获得更好的使用体验,同时这也掩盖了真正的问题,迷惑了使用 Chrome 浏览器的 Hugo 主题开发者.
找到问题的根源 ¶
核心的思路仍然是理解浏览器渲染页面的流程. 简单来说:
- 你请求了一个网页;
- 浏览器先把整个 HTML 下载下来,存成 DOM,然后从上到下依次解析、渲染页面;
- 遇到外链的 CSS 或 JavaScript 就停止解析,先去把外链的文件下载回来装载上再继续;
- 遇到
<style></style>
或刚刚装载了外部的 CSS 就把样式表存成 CSSOM 并重新渲染有影响的部分; - 遇到
<script></script>
或刚刚装载了外部的 JavaScript 就停止解析并运行脚本,运行完脚本后再继续解析、渲染; - 以此类推,直到完成.
而发生闪烁问题的原因就在于我把判断颜色的 JavaScript 脚本放在了 <body>
的最后,像这样:
|
|
解决 ¶
问题的解决其实也简单,核心有二:
- 把读取主题的脚本放进
<head>
里,这样刚刚加载还没开始渲染时就能够确定用户当前选择的主题;
- 把读取主题的脚本放进
- 把更改主题的容器提升成整个
<html>
,即:从原来的
- 把更改主题的容器提升成整个
|
|
变成现在的
|
|
这是因为 <body>
在这个时候还没有被渲染,<head>
里的脚本能操作的对象只有 <html>
.
至此问题完全解决,完整的代码如下:
|
|
友情链接(该栏目下的其他文章)
- 第 1 期:Hugo 静态博客建站记 - 自写主题
- 第 2 期:博客记录书影音——Hugo 的 Data Templates - 自写主题
- 第 3 期:如何让静态网站的暗色主题换页不闪烁 - 自写主题(就是这篇!)
- 第 4 期:Hugo 如何让图片在暗色主题下反色 - 自写主题