高效的移动HTML暗黑模式主题切换。

3

我一直在寻找一种既可以自动切换又可切换的移动端高效暗黑模式主题。通过“移动端高效”,我指的是高延迟、低带宽、低CPU占用:

  • 仅在需要时加载相关样式表(当浅色模式激活时,不会加载暗黑样式表,反之亦然),以节省带宽
  • 无全屏闪烁
  • 无 cookie

我发现的解决方案没有这些属性,它们要么使用一个灰色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?

1个回答

1
如何将“is-dark”类添加到html标签中?为了使您的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

我也尝试过,它既有较臃肿的CSS,也有瞬态闪烁问题(当CSS已经在缓存中时,在较慢的设备上,浏览器会偶尔在JS添加类之前应用它,或者如果某些内容阻碍了JS(例如没有缓存JS)。即使JS是第一个body元素,页面背景(仍为空)也可能会闪烁黑/白... - Eric Grange
你确定你按照我的建议做了吗?我编辑了我的答案以展示我的意思。如果你使用自定义属性,你只需要为“.is-dark”重新声明它们,这只是在你的样式表中非常少量的重复(你只需要一个!) - 而且它将被(希望)压缩。所以我无法想象会有任何值得注意的膨胀,并且不会出现闪烁的内容。当你添加那个类时,浏览器将立即呈现颜色。 - Floyd
“.is-dark” 是用于开关的,当然了。你也可以使用媒体查询来实现同样的效果:@media (prefers-color-scheme: dark) { … } - Floyd
SASS:在SASS中使用自定义属性没有任何问题。只需替换颜色值即可 ;) Flicker:据我所知,有三种可能的情况:第一种:根本没有深色主题-没有闪烁。第二:通过媒体查询使用深色主题-在评估媒体查询后将呈现页面-没有闪烁。第三:用户选择切换到深色主题并使用开关-他只能在页面呈现后才能这样做。添加类的那一刻,浏览器将立即呈现新的颜色-没有闪烁。我错过了什么吗? - Floyd
1
“阻止渲染”正是这里推荐的做法:https://dev59.com/X1IG5IYBdhLWcg3ww0VR - Floyd
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接