hexo博客next主题添加夜间模式(Dark Mode)

本文主要介绍为hexo next主题添加一个可以切换的黑色/夜间模式,虽然next 8.0 主题已经支持原生黑色模式,但是这个黑色模式是不可以切换的。本文介绍如何实现按钮来切换,包括如何在代码部分也切换夜间模式。

效果

费话不多说,先上效果

特点:

  • 代码部分进行Dark/Light模式切换
  • 切换有动画
  • code部分进行优化

前题

首先,你要确定自己的Hexo与next的版本:

Hexo在这里:hexojs/hexo,我们使用的版本是:5.4.0

Next主题在这里:next-theme/hexo-theme-next,我们使用的版本是:8.2.2

虽然next 8.0 主题已经支持原生黑色模式,只需要在_config.yml文件中,将相应开关打开darkmode: true即可。

但是这个黑色模式是不可以切换的,本文将介绍如何实现一个按钮来切换黑/白模式。

我们使用的主题是:scheme: Mist,其他类似思路进行调整。

步骤

思路:

  1. 使用第三方的包实现切换darkmode主题
  2. 切用next主题已经有的dark模式,为代码高亮部分添加样式

了解darkmode.js

我们主要使用到了这个库Darkmode.js 来实现整体切换效果,在官方的github上有使用方式的介绍。

下载并配置next主题

我们要集成到hexo中时,需要考虑是使用本地的js还是cdn的js,我的方式是下载到lib目录中,使用本地的,以免出现后续的依赖问题。

themes/next/_vendors.yml 中指定darkmode-js的文件:

1
2
3
4
darkmode_js:
name: darkmode-js
version: 1.5.7
file: lib/darkmode-js.min.js

next主题的的 _config.yml文件中,添加darkmode_js的相关开关:

1
2
3
4
5
6
7
vendors:
# 使用CDN可选,darkmode_js: https://cdn.jsdelivr.net/npm/darkmode-js/lib/darkmode-js.min.js
darkmode_js:

# darkmode.js
darkmode_js:
enable: true

注意缩进!第一个darkmode_js是在vendors栏目下,第二个darkmode_js是一个单独的栏目。

修改主题模板

打开 themes/next/layout/_scripts/vendors.njk,配置以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
{%- if theme.canvas_ribbon.enable %}
<script size="{{ theme.canvas_ribbon.size }}" alpha="{{ theme.canvas_ribbon.alpha }}" zIndex="{{ theme.canvas_ribbon.zIndex }}" src="{{ theme.vendors.canvas_ribbon }}"></script>
{%- endif %}

{# Customize darkmode.js - Declaration #}
{%- if theme.darkmode_js.enable %}
<script src="{{ theme.vendors.darkmode_js }}"></script>
{%- endif %}

{%- for name in js_vendors() %}
<script src="{{ url_for(theme.vendors[name]) }}"></script>
{%- endfor %}

{# Customize darkmode.js - Invokation #}
{%- if theme.darkmode_js.enable %}
<script>
var options = {
bottom: '64px', // default: '32px'
right: 'unset', // default: '32px'
left: '32px', // default: 'unset'
time: '0.5s', // default: '0.3s'
mixColor: '#fff', // default: '#fff'
backgroundColor: '#fff', // default: '#fff'
buttonColorDark: '#100f2c', // default: '#100f2c'
buttonColorLight: '#fff', // default: '#fff'
saveInCookies: true, // default: true,
label: '🌓', // default: ''
autoMatchOsTheme: true // default: true
}
const darkmode = new Darkmode(options);
darkmode.showWidget();
</script>
{%- endif %}

这里主要是在全局加入了一段初始化darkmode-js的代码。

重新生成即可开启:

1
2
hexo clean && hexo g
hexo s

初步效果

致命问题,没有对代码块highlight部分生效。

代码Dark主题

next的8.0开始,已经有了dark主题,直接可以_config.xml,参考:issues#1395

但是,按照官方的设置了之后,无法动态的切换了。

继续深挖官方的代码,有一个非常重要的文件source/css/_colors.styl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
:root {
--body-bg-color: $body-bg-color;
--content-bg-color: $content-bg-color;
--card-bg-color: $card-bg-color;
--text-color: $text-color;
--blockquote-color: $blockquote-color;
--link-color: $link-color;
--link-hover-color: $link-hover-color;
--brand-color: $brand-color;
--brand-hover-color: $brand-hover-color;
--table-row-odd-bg-color: $table-row-odd-bg-color;
--table-row-hover-bg-color: $table-row-hover-bg-color;
--menu-item-bg-color: $menu-item-bg-color;

--btn-default-bg: $btn-default-bg;
--btn-default-color: $btn-default-color;
--btn-default-border-color: $btn-default-border-color;
--btn-default-hover-bg: $btn-default-hover-bg;
--btn-default-hover-color: $btn-default-hover-color;
--btn-default-hover-border-color: $btn-default-hover-border-color;

--highlight-background: $highlight-background;
--highlight-foreground: $highlight-foreground;
--highlight-gutter-background: $highlight-gutter-background;
--highlight-gutter-foreground: $highlight-gutter-foreground;
}

if (hexo-config('darkmode')) {
@media (prefers-color-scheme: dark) {
:root {
--body-bg-color: $body-bg-color-dark;
--content-bg-color: $content-bg-color-dark;
--card-bg-color: $card-bg-color-dark;
--text-color: $text-color-dark;
--blockquote-color: $blockquote-color-dark;
--link-color: $link-color-dark;
--link-hover-color: $link-hover-color-dark;
--brand-color: $brand-color-dark;
--brand-hover-color: $brand-hover-color-dark;
--table-row-odd-bg-color: $table-row-odd-bg-color-dark;
--table-row-hover-bg-color: $table-row-hover-bg-color-dark;
--menu-item-bg-color: $menu-item-bg-color-dark;

--btn-default-bg: $btn-default-bg-dark;
--btn-default-color: $btn-default-color-dark;
--btn-default-border-color: $btn-default-border-color-dark;
--btn-default-hover-bg: $btn-default-hover-bg-dark;
--btn-default-hover-color: $btn-default-hover-color-dark;
--btn-default-hover-border-color: $btn-default-hover-border-color-dark;

--highlight-background: $highlight-background-dark;
--highlight-foreground: $highlight-foreground-dark;
--highlight-gutter-background: $highlight-gutter-background-dark;
--highlight-gutter-foreground: $highlight-gutter-foreground-dark;
}

img {
opacity: .75;

&:hover {
opacity: .9;
}
}
}
}

原来切换深色与否是切换了基础的变量,那么怎么与darkmode-js`结合呢?

A CSS class darkmode--activated is added to the body tag when the darkmode is activated. You can take advantage of it to override the style and have a custom style

darkmode被激活的时候,会在body上添加一个darkmode--activated的类,那么如果我们把上面的样式添加到它的下面,是不是就实现了dark模式的切换?

首先,修改文件next/source/css/_colors.styl,把:root修改成body

1
2
3
4
body {
--body-bg-color: $body-bg-color;
--content-bg-color: $content-bg-color;
// ..

然后添加文件next/source/css/_common/scaffolding/darkmode.styl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
.darkmode--activated{
--body-bg-color: $body-bg-color-dark;
--content-bg-color: $content-bg-color-dark;
--card-bg-color: $card-bg-color-dark;
--text-color: $text-color-dark;
--blockquote-color: $blockquote-color-dark;
--link-color: $link-color-dark;
--link-hover-color: $link-hover-color-dark;
--brand-color: $brand-color-dark;
--brand-hover-color: $brand-hover-color-dark;
--table-row-odd-bg-color: $table-row-odd-bg-color-dark;
--table-row-hover-bg-color: $table-row-hover-bg-color-dark;
--menu-item-bg-color: $menu-item-bg-color-dark;

--btn-default-bg: $btn-default-bg-dark;
--btn-default-color: $btn-default-color-dark;
--btn-default-border-color: $btn-default-border-color-dark;
--btn-default-hover-bg: $btn-default-hover-bg-dark;
--btn-default-hover-color: $btn-default-hover-color-dark;
--btn-default-hover-border-color: $btn-default-hover-border-color-dark;

--highlight-background: $highlight-background-dark;
--highlight-foreground: $highlight-foreground-dark;
--highlight-gutter-background: $highlight-gutter-background-dark;
--highlight-gutter-foreground: $highlight-gutter-foreground-dark;

img {
opacity: .75;

&:hover {
opacity: .9;
}
}
}

最后就是引入next/source/css/_common/scaffolding/index.styl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//
// Scaffolding
// ==================================================
@import 'normalize';
@import 'base';
@import 'tables';
@import 'buttons';
@import 'toggles';
@import 'highlight';
@import 'tags';
@import 'pagination';
@import 'comments';
// 这里引入
@import 'darkmode';

实现效果:

优化

上面,显示的代码块code部分,不太完美,而且,对于头部也不太完美,所以我们进行样式上的调整:

1
2
3
4
5
6
7
8
9
10
11
12
13
.darkmode--activated{
// ..

// 优化内容
code {
color: #69dbdc;
background: transparent;
}

.header {
background: #fff
}
}

本文完。