在网站上实施暗黑模式主题时,需要考虑很多因素。 我们有 一个完整的指南。 有一些 非常聪明的快速解决方案,但也有不少相当棘手的事情需要完成。 其中一件棘手的事情是,它不是暗黑模式与亮色模式之间的“切换”,而是真正需要支持的 *三种* 模式:**暗黑**、**亮色** 和 *使用系统偏好设置*。 这类似于许多应用程序中的音频首选项,允许您非常具体地选择所需的音频输入或输出,或者默认使用系统偏好设置。
CSS 和 JavaScript 可以通过 prefers-color-scheme
API 处理系统偏好设置的角度,但是如果用户偏好设置已更改,并且该偏好设置现在与用户偏好设置不同,则您将处于“不准确颜色主题闪现”或 FART 的领域。 好吧好吧,这是一个调侃的缩写词,但它可能是一个非常令人反感的视觉问题,所以我保留了它。 它与 FOUT (无样式文本闪现) 用于字体加载的方式类似。
存储用户偏好设置意味着类似于 Cookie、localStorage
或某种数据库。 如果访问该数据意味着运行 JavaScript,例如 localStorage.getItem('color-mode-preference');
,那么您就处于 FART 领域,因为您的 JavaScript 很可能在页面首次渲染 *之后* 运行,除非您不必要地延迟页面渲染。
您可以在页面渲染之前使用服务器端语言访问 Cookie,这意味着您可以使用它输出类似于 <html class="user-setting-dark-mode">
的内容并相应地进行样式设置,这巧妙地避免了 FART,但这意味着一个网站,即使可以访问服务器端语言(例如 Jamstack 网站就无法访问)。
以上所有这些都是为了说明我对 Rob Morieson 关于暗黑模式的文章 的赞赏,因为它没有回避这个重要问题。 它非常具体地介绍了在 Next.js 中执行此操作的方法,并使用 localStorage
,但由于 Next.js 是 JavaScript 渲染的,因此您可以强制它将检查用户保存的偏好设置作为它执行的第一件事。 这意味着它会在第一次渲染时正确显示(没有闪现)。 但是您确实需要关闭服务器端渲染才能使它工作,这虽然是一个棘手的权衡。
我不相信除了服务器端语言或强制延迟页面渲染之外,还有其他好的方法可以避免 FART。
这个问题有多严重,以至于都没有提及?
const theme = localStorage.getItem(‘color-mode-preference’) || ‘system’
document.body.classList.add(`theme-setting-${theme}-mode`)
这就是重点。 该 JavaScript 很可能在页面渲染 *之后* 运行。
哦,我忘了说在打开标签之后放这个。 对不起。
const theme = localStorage.getItem(‘color-mode-preference’) || ‘system’
document.body.classList.add(`theme-setting-${theme}-mode`)
现在我看到其他人也建议这样做。
这个缩写词。 太棒了。
解决这个问题的一种棘手方法是使用服务工作者和缓存 API 来更新请求时检索到的 css 文件。 这将是一件很有趣的事情。
这可能实际上是使用服务工作者的一个好方法,尤其是在您已经使用它的情况下。 如果有人明确选择了暗黑模式或亮色模式的偏好设置,您可以拦截他们对主样式表的网络请求(该样式表将包含“prefers-color-scheme”媒体查询)并用只有指定颜色方案样式的样式表的缓存版本覆盖它。
我不确定我是否理解关于 localstorage 的部分。 Next.js 是 React 在服务器端(Node.js)上的运行,因此您应该使用 Cookie 来执行此操作,而不是 localStorage,因为它仅在客户端可用。
这是在 Nuxt.js 上的此功能的基本实现。 等同于 Next.js,但适用于 Vue。 使用 Cookie 并在服务器端执行此操作实际上要好得多,因为它不会阻止页面渲染,直到 JS 被解析并执行。
您可以在页面的头部放一个像这样的脚本,我认为延迟并不大。
像 https://mxb.dev/ 这样的网站,或者我的网站已经使用了这种技术。
在知道用户主题偏好设置之前,完全隐藏页面怎么样? 使用中间灰色作为过渡,然后在可能的情况下淡入亮色主题或暗黑主题…
这就是我说的强制延迟。 感觉为了这个付出的代价太大了。
此外,‘no-js-no-content’ 是过去几年中网络上最糟糕的发展之一。
如果您必须隐藏页面,请使用类似于
body.preloader
的内容在标记中; 并在 CSS 中是的。 我希望看到这个问题不再被忽视。 我甚至可以接受默认情况下将 body 背景设置为暗黑模式,因为 - 如果出现 FART - 偏爱明亮颜色的人不会像相反情况发生那样受到伤害。
https://twitter.com/hotplinth/status/1382844581486682118
我认为,在 HTML 头部放置一小段内联 JS 来从 Cookie 或 localStorage 加载用户偏好设置,在渲染方面不会造成太大延迟。
是的,我同意。 我还看到一个小的脚本标签被放置在 body 标签中的第一个元素,其中检查主题偏好设置并进行相应的操作。 我不会说它会以明显的方式影响渲染……至少与我们每天做的其他事情相比是如此。
只需确保在任何
<link rel="stylesheet">
和<style>
标签之前放置暗黑模式 CSS 类我不相信不准确颜色主题的闪现是主要问题。 从我所见
在黑暗的房间里关着灯,暗黑主题加载之前出现白色闪现非常令人不快。
在白天在户外观看黑色屏幕的闪现,看起来只是屏幕的一部分在很短的时间内关闭了。
考虑到这种不对称性,将这个问题重新思考为“白色闪现应尽可能避免;黑色闪现要好得多”,并开始编写以暗黑模式优先的样式表,岂不更好?
我还没有在 FOUT 是我被要求解决的问题的网站上工作过,但可以考虑一下
这样,页面在浏览器开始绘制任何内容之前就会获得白底黑字的颜色方案,而且没有人会在床上被闪瞎。
嗨,我尝试找到解决这个问题的变通方法。
https://medium.com/@lyxsus/fixing-fart-flash-of-inaccurate-color-theme-for-static-websites-7935f7f85e20
我之前一段时间会在文档开头添加一个脚本标签,这有助于绕过闪屏,而不会对性能造成明显影响。我在这篇文章中写到了它
https://blog.jim-nielsen.com/2018/icon-galleries-dark-mode/
当然,它需要使用 JavaScript。最终,我通过移除黑暗模式的 UI 切换并完全依赖于 prefers-color-scheme 来删除此功能,这绕过了对服务器端渲染或 JS 技巧来持久化黑暗或浅色模式切换状态的需要。
现在有一个新的提案来防止 FART:https://github.com/WICG/user-preference-media-features-headers
这将允许在初始请求头中添加用户偏好(如首选颜色方案)。