首页 > 解决方案 > 使用移动 HTML 切换的高效暗模式主题

问题描述

我一直在寻找拥有移动高效黑暗模式主题的方法,它既是自动的,又可以切换。移动效率是指高延迟、低带宽、低 CPU 友好:

我发现的解决方案没有这些属性,它们要么使用结合了两个主题的胖 CSS,要么使用两个样式表,当用户选择与系统默认不同的主题时,这可能会导致全屏闪烁(因为它们是通过在 DOM 中引用样式表后执行的 JS 来控制的)。

到目前为止,我最好的选择是“高效”,但依赖于 document.write 在文档头中的一个小内联脚本中,它类似于:

let theme = localStorage.getItem("theme");
if (!theme) {
   theme = (window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches)?"dark":"light"
}
if (theme == "dark") {
   document.write('<link rel="stylesheet" href="dark.theme.css" />');
} else {
   document.write('<link rel="stylesheet" href="light.theme.css" />');
}

当用户手动切换时,localStorage 条目由常规 JS 管理。

我尝试了所有方法来改变链接 DOM 元素,但它们都失败了,导致 CSS 加载闪烁或延迟(未呈现的 HTML 暂时可见)。

我想知道是否有一种方法仍然有效,支持切换而不依赖 document.write ?

标签: htmlcssmedia-queriesdarkmode

解决方案


在 html 标签中添加一个“is-dark”类怎么样?为了使您的 css 尽可能精简,您可以将所有颜色定义为 css 自定义属性,并在“is-dark”范围内重新定义它们。因此,您只需交付这些自定义属性两次,这应该是可管理的。

你仍然需要 JS 来添加类,但你不需要 document.write。这将消除三种情况中的两种情况下的闪烁,即当通过媒体查询选择深色主题时以及使用开关选择它时。

所以这看起来像这样:

:root {
  --clr-primary:                      #8e211a;
  --clr-secondary:                    #5e737a;
…
}


.is-dark {
  --clr-primary:                      black;
  --clr-secondary:                    white;
}


.myElement {
  color: var(--clr-secondary);
  background-color: var(--clr-primary);
}

这给我们留下了第三种情况的问题:在重新加载之前每次切换选择黑暗主题时重新加载后闪烁。在这种情况下,将使用浅色主题,直到 JS 命中并将其切换为深色主题。

最好的选择似乎是在 JS 准备好之前阻止页面渲染,如此线程所示:Dark mode flickers a white background for a millisecond on reload


推荐阅读