我如何在我的网站上添加黑暗模式

129 阅读4分钟

Dark mode

媒体查询5级规范包含一个新的 prefers-color-scheme媒体功能。

目前所有的主要浏览器都支持这个功能。Chrome/Edge自76版起,Firefox自67版起,Safari(自12.1版)。甚至是iOS Safari。

我们可以用它来判断用户是在黑暗还是光明模式下浏览网页。

@media (prefers-color-scheme: dark) {
  body {
    background-color: black;
    color: white;
  }
}
@media (prefers-color-scheme: light) {
  body {
    background-color: white;
    color: black;
  }
}

我现在用它来显示网站的默认浅色版本,如果系统是在黑暗模式下,则显示深色版本。

如果系统没有内置黑暗模式(老式Windows / macOS,Linux),那么我的建议是使用像Night Eye或类似的扩展。

prefers-color-scheme ,我是如何实现黑暗模式的

我最近重新设计了我的网站。这里有两张图片是它的样子,供参考。

Old homepage

Old post page

我在近一年前设计了这个网站,并在此过程中做了许多改动,就像我们做任何网站一样。

最终我对这个设计感到厌倦:标题太大,失去了太多的空间,而不是直接显示内容,等等。

昨天晚上我坐下来,开始重新设计网站,今天早上我完成了重新设计。

New homepage

New post page

好多了!内容,最重要的东西,更加突出。

我使用了一种单行字体(Inconsolata),因为作为一个编程博客,它是一个不错的字体,尽管由于字体的使用,可读性降低,页面大小增加,因为我在我的网站上使用这种字体。我比较喜欢它,由于我的网站是我日常活动的一个重要部分,我希望它能像我想要的那样。

我只是错过了一件事:黑暗模式。当我在重新设计的过程中,我想到了黑暗模式的选项。

我是怎么做的呢?首先,我在侧边栏中添加了Moon Emoji 🌓,作为一种让人们将模式从浅色变为深色的方式。

然后,我添加了一个JavaScript片段,当它被点击时运行。我只是把它添加到HTML中的onclick 事件处理程序中,而没有进行更复杂的处理。

<p>
  <a href="#" onclick="localStorage.setItem('mode', (localStorage.getItem('mode') || 'dark') === 'dark' ? 'light' : 'dark'); localStorage.getItem('mode') === 'dark' ? document.querySelector('body').classList.add('dark') : document.querySelector('body').classList.remove('dark')" title="Dark/light
</p>

这是运行于onclick的JavaScript。

localStorage.setItem('mode', (localStorage.getItem('mode') || 'dark') === 'dark' ? 'light' : 'dark'); localStorage.getItem('mode') === 'dark' ? document.querySelector('body').classList.add('dark') : document.querySelector('body').classList.remove('dark')

这有点复杂,但基本上我检查本地存储中的mode 属性是否为 "dark"(如果还没有设置,则默认为dark,使用|| 操作符),并在本地存储中设置与之相反的属性。

然后我把dark 类分配给body HTML元素,这样我们就可以使用CSS来为页面设置暗色模式的样式。

另一个脚本在DOM加载时立即运行,并检查模式是否为暗色。如果是,它就把dark 类添加到body HTML元素中。

document.addEventListener('DOMContentLoaded', (event) => {
  ((localStorage.getItem('mode') || 'dark') === 'dark') ? document.querySelector('body').classList.add('dark') : document.querySelector('body').classList.remove('dark')
})

现在,如果人们改变模式,他们的选择将在下次加载页面时被记住。

然后,我在CSS中添加了很多CSS指令,都以body.dark 为前缀。像这些。

body.dark {
  background-color: rgb(14,20,10);
  color: #fff;
}
body.dark code[class*=language-],
body.dark table tbody>tr:nth-child(odd)>td,
body.dark table tbody>tr:nth-child(odd)>th {
  background: #282c34
}

现在事情应该已经开始工作了这是我在黑暗模式下的网站。

Dark homepage

Dark post page

我把dark 类默认添加到body 元素中,以使黑暗模式成为默认模式。

<body class="dark">
  ...
</body>

为什么?首先,我更喜欢它。然后,我在Twitter上做了一个投票,人们更喜欢它。

Poll

但也有一个技术原因,实际上是一个非常简单的原因。我不在服务器端存储用户的选择,所以在本地存储之前,我没有办法知道模式的情况。

如果网站是在服务器端生成的,我可以做到这一点,但这是一个静态网站,所以我总是向每个请求它的人提供相同的页面。即使我得到了一个cookie,我也没有地方去处理它(从另一个角度看,这意味着我的页面加载速度更快)。

因此,当有人在我的网站上导航到另一个页面,或在第二次访问时首次加载该页面时,我不想在确定模式时显示一个明亮的页面。也许访问者是在半夜里在一个黑暗的房间里编码的。

我宁愿在光明模式下这样做:显示一个黑暗的页面几毫秒,然后再把它变成白色。