面向小白的Hexo添加暗色模式教程

美少女万华镜4

OPPO手机都有暗色模式了,你的博客居然还没有。

更新记录

2020/04/17

目前安卓上就chrome能正常使用媒体查询。其他浏览器即使内核支持但是没效果。

转载请带上出处,别用没有照抄这个理由来敷衍我。

封面与内容无关,我找不到好看的封面图了。555

valine真是让我无语了。这篇文章一直出不来评论框,找了10几分钟原因发现是代码块里不能写注释。。

在tg群看见别人给博客加上了暗色模式,搜索一番得出下面几个方案。

  • prefers-color-scheme 媒体查询
  • 给body加class
  • disabled配合备用css

虽然媒体查询的方法好用 , 但是 不兼容低版本浏览器和系统 . 最重要的是不够灵活 .

disabled配合备用css 之前我用的就是这个方法 , 不需要动原css 操作方便 , 缺点就是增加了一个请求,并且按钮第一次点击没反应 . (不推荐使用)

安卓的暗色模式好像都是黑白高对比度的瞎眼模式 , oled屏幕再开启DC调光导致低亮度偏色,配合oled屏幕的纯黑背景的拖影…我用了一次就再也没有开启过暗色模式 . 各位选配色的时候记住不要学这种反面例子 .

win 10开启暗色模式 , 个性化–>颜色–>默认应用模式 .

prefers-color-scheme Safari(v12.1及以上版本),Chrome(v76及以上版本)和Firefox(v67及以上版本)都支持 .

我手机 ColorOS 7 , 安卓10 , 系统webview版本80 , 使用套壳的via浏览器发现这个媒体查询在vai上无效 . 测试了很多浏览器就chrome能正常显示 . 而且在不同安卓好像对app的暗色模式还有单独按钮开启 . 导致这个媒体查询几乎就是个摆设 .

在via的issues看见有人反馈过这个问题。开发者说3.9.9版本处理,但是我更新到这个版本也没效果。其他浏览器大概也是这个原因吧。

写了个测试页面 , 开启暗色模式后打开页面 , 看到的div背景色是粉色则说明不支持媒体查询 .

div下面3行文本是通过js判断暗色模式是否开启 , 如果开启了暗色模式 , 正常情况应该是输出 true false “dark” .

暗色模式是否正常测试页面 请右键新标签打开查看 . 因为有pjax会直接在本页打开...

prefers-color-scheme 媒体查询

这应该是省事的方案 , 但目前安卓手机上只有chrome支持。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
:root {
--background-color: #ededed;
--page-background: #fff;
--text-color: #212121;
--color-alpha: #c3423f;
}
@media (prefers-color-scheme: dark) {
:root {
--background-color: #111;
--page-background: #212121;
--text-color: #ededed;
--color-alpha: #50a8d8;
}
}
body {
background-color: var(--background-color);
color: var(--text-color);
}

这种方案就是在全局定义好 css的变量 , 媒体查询检测到系统是暗色模式就会给变量重新赋值 .

也可以不使用css变量,直接在媒体查询里写覆盖的样式.

class

在媒体查询之前很多博客的暗色模式都是使用这个方案 . 不依赖媒体查询 .

参照几篇博客的文章折腾了一下 . 与上面的 媒体查询方案二选一 , 不要重复使用 .

参考过的文章好像都是动态博客 , 他们都使用cookie判断是否手动开启了暗色模式 , 但静态博客没必要使用cookie . 我改为使用localStorage . 并且 使用 matchMedia('(prefers-color-scheme: dark)').matches 判断当前环境是否暗色模式来兼容媒体查询方案 .。

需要配合后面的js才有效 . 原来的css不需要改动 , 覆盖的样式在css 选择器前面加上 body.dark

1
2
3
4
5
body.dark {background: #2f3742;}
body.dark .aplayer{background: #2f3742!important;}
body.dark img {
filter: brightness(50%);
}

aplayer valine要加!important才能让css生效。

这种方法也可以使用css变量 , 不过变量重新赋值不能写在媒体查询里 , 因为系统没有开启暗色模式就没办法重新赋值 . 可以在 :root body.dark 里重新赋值可能记错了

虽然使用css变量很方便维护, 但是把原来固定的值一个个改为变量也很麻烦, 所以我选择不使用变量 , 直接写样式覆盖 . 全部替换我不敢用,一个颜色在几个地方使用就会出问题…

与之前css配合的js部分

在主题的layout.ejs文件中找到body标签的开始标签在后面加上这些js .

1
2
3
4
5
6
7
if (localStorage.getItem('dark') === '1') {
document.body.classList.add('dark');
} else if (new Date().getHours() >= 22 || new Date().getHours() < 7) {
document.body.classList.add('dark');
} else if (matchMedia('(prefers-color-scheme: dark)').matches) {
document.body.classList.add('dark');
}

手动,时间范围,媒体查询我都用了. 有不需要的部分自行删减. 必须得是body开始标签后面,放head里不行,因为文档还没有渲染到body,放页面底部后面会导致页面闪白时间太长。没有使用pjax的博客建议不要给背景色变化加过渡,每个页面都是独立的,加了过渡动画会导致每次切换页面都播放过渡效果.

到这里利用class添加暗色模式已经完成了,其实和媒体查询方案差不多 , 只是覆盖原css的样式没有写在媒体查询里而已.

暗色模式切换按钮

屏幕左下角的小埋是手动开关,以前看到过别人博客底部的蕾姆,拉姆的至顶至底按钮正好合适拿来作夜间模式开关,翻友链里别人的博客,雷姆没有找到,小埋倒是有一只 .

1
2
3
<div id="xm">
<img src="/images/xm.png">
</div>

按钮的css

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#xm {
cursor: pointer;
position: fixed;
bottom: 0;
left: 0;
z-index: 1;
font-size: 0;
transition: all 0.3s ease-in-out;
transform: translateY(3px);
}
#xm:hover {
transform: translateY(0);
}
#xm img {
width: 50px;
}

按钮的js , 添加到body底部或者独立的js文件都可以.

1
2
3
4
5
6
7
8
9
10
11
12
function switchNightMode() {
var body = document.body;
if(body.classList.contains('dark')){
document.body.classList.remove('dark');
localStorage.setItem('dark','0');
} else {
document.body.classList.add('dark');
localStorage.setItem('dark','1');
}
}
var xm = document.getElementById("xm");
xm.onclick = switchNightMode;

小埋的图右键从我这里另存为就可以了 . 自己搞个喜欢的按钮也行 .

同样是白色 #fff 在chrome下比firefox更暗,firefox不支持改变滚动条样式,简直丑爆了。

同一个局域网内 , hexo s 后在手机浏览器打开 http://ip:4000 就可以在手机上预览效果 . ip就是电脑的局域网ip .

折腾时参考过的文章如下