【问题标题】:Efficient dark mode theming with toggle for mobile HTML使用移动 HTML 切换的高效暗模式主题
【发布时间】:2021-10-16 14:21:05
【问题描述】:

我一直在寻找具有移动效率暗模式主题的方法,该主题既是自动的,又可以切换。移动效率是指高延迟、低带宽、低 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 ?

【问题讨论】:

    标签: html css media-queries darkmode


    【解决方案1】:

    如何在 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

    【讨论】:

    • 我也试过了,它的缺点是 CSS 比较大,而且会出现瞬态闪烁(当 CSS 已经在缓存中时,浏览器偶尔会在 JS 将类添加到较慢的设备,或者如果某些东西阻碍了 JS(比如 JS 不在缓存中)。即使 JS 是第一个 body 元素,(仍然是空的)页面背景也会闪烁黑/白...
    • 你确定你按照我的建议做了吗?我编辑了我的答案以表明我的意思。如果您使用自定义属性,您只需将它们重新声明为“.is-dark”,这只是您的样式表中的少量重复(您只需要一个!) - 它会(希望)gzipped反正。所以我无法想象会有任何值得注意的腹胀,并且不会有闪烁的内容。添加该类的那一刻,浏览器将立即呈现颜色。
    • ".is-dark" 当然是用于开关。您可以对媒体查询执行相同操作:@media (prefers-color-scheme: dark) { ... }
    • 我使用的主题是引导布局,这意味着 SASS,这意味着它非常冗长(最终他们会放弃 SASS 并使用 CSS 变量,但我们还没有实现)。但是,这对于加载样式表(如果在缓存中可以是即时的)和 JS 运行的时间(可以很短,但不为零)之间的时间间隔仍然无济于事。 document.write 阻塞了主线程,这也是防止闪烁的原因。
    • 嗯,“阻塞渲染”正是这里推荐的:stackoverflow.com/questions/63033412/…
    猜你喜欢
    • 1970-01-01
    • 2021-12-09
    • 2021-08-19
    • 1970-01-01
    • 2020-09-12
    • 2021-07-06
    • 2015-03-22
    • 1970-01-01
    • 2021-06-25
    相关资源
    最近更新 更多