Hexo Next 8.x 主题添加可切换的暗黑模式

前言

Next 8.x 原生的暗黑模式

Next 8.x 主题已经原生支持暗黑模式,只需要在 Next 的 _config.yml 配置文件中,将相应的开关打开即可(如下所示):

1
darkmode: true

Next 8.x 主题原生暗黑模式的优缺点:

  • 优点:
    • 配置非常简单
  • 缺点:
    • 缺少切换按钮,默认是根据系统偏好(系统是否处于暗黑模式)来决定是否启用

Next 7.x 添加可切换的暗黑模式

若读者使用的 Next 版本是 7.x,建议直接安装 hexo-next-darkmode 插件来自动添加可切换的暗黑模式,具体的安装步骤与下面讲述的教程: Next 8.x 自动添加可切换的暗黑模式 一致,最终演示效果可以看这里

Next 8.x 自动添加可切换的暗黑模式

hexo-next-darkmode 插件支持自动添加可切换的暗黑模式,同时支持暗黑模式下的 CSS 样式高度自定义,包括自定义代码块颜色切换等,兼容 Next 7.x 与 8.x 版本。

安装 Hexo 插件

安装 hexo-next-darkmode 插件

1
$ npm install hexo-next-darkmode --save

配置 Hexo 插件

在 Next 主题的 _config.yml 配置文件里添加以下内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# Darkmode JS
# For more information: https://github.com/rqh656418510/hexo-next-darkmode, https://github.com/sandoche/Darkmode.js
darkmode_js:
enable: true
bottom: '64px' # default: '32px'
right: 'unset' # default: '32px'
left: '32px' # default: 'unset'
time: '0.5s' # default: '0.3s'
mixColor: 'transparent' # default: '#fff'
backgroundColor: 'transparent' # default: '#fff'
buttonColorDark: '#100f2c' # default: '#100f2c'
buttonColorLight: '#fff' # default: '#fff'
isActivated: false # default false
saveInCookies: true # default: true
label: '🌓' # default: ''
autoMatchOsTheme: true # default: true
libUrl: # Set custom library cdn url for Darkmode.js
  • isActivated: true:默认激活暗黑 / 夜间模式,请始终与 saveInCookies: falseautoMatchOsTheme: false 一起使用

关闭原生的暗黑模式

确保 Next 原生的 darkmode 选项设置为 false,在 Next 的 _config.yml 配置文件中更改以下内容:

1
darkmode: false

暗黑模式 CSS 样式自定义

暗黑模式激活后,hexo-next-darkmode 插件会将 darkmode--activated CSS 类添加到 body 标签,可以利用它覆盖插件默认自带的 CSS 样式(如下所示);这样就可以实现暗黑模式 CSS 样式的高度自定义,包括代码块颜色自定义切换等。更多配置内容介绍可以参考官方文档,实现原理分析可以看这里

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
.darkmode--activated {
--body-bg-color: #282828;
--content-bg-color: #333;
--card-bg-color: #555;
--text-color: #ccc;
--blockquote-color: #bbb;
--link-color: #ccc;
--link-hover-color: #eee;
--brand-color: #ddd;
--brand-hover-color: #ddd;
--table-row-odd-bg-color: #282828;
--table-row-hover-bg-color: #363636;
--menu-item-bg-color: #555;
--btn-default-bg: #222;
--btn-default-color: #ccc;
--btn-default-border-color: #555;
--btn-default-hover-bg: #666;
--btn-default-hover-color: #ccc;
--btn-default-hover-border-color: #666;
--highlight-background: #282b2e;
--highlight-foreground: #a9b7c6;
--highlight-gutter-background: #34393d;
--highlight-gutter-foreground: #9ca9b6;
}

.darkmode--activated img {
opacity: 0.75;
}

.darkmode--activated img:hover {
opacity: 0.9;
}

.darkmode--activated code {
color: #69dbdc;
background: transparent;
}

重新构建生成静态文件

Hexo 重新构建生成静态文件后,点击页面上的按钮即可切换暗黑模式,最终演示效果可以看这里

1
2
3
$ hexo clean

$ hexo g -d

Next 8.x 手动添加可切换的暗黑模式

关闭原生的暗黑模式

确保 Next 原生的 darkmode 选项设置为 false,在 Next 的 _config.yml 配置文件中更改以下内容:

1
darkmode: false

添加 JS 库 Darkmode.js

下载 darkmode.js 或者直接添加 CDN 配置到 Next 的 themes/next/_vendors.yml 文件末尾,这里采用 CDN 配置的方式(如下所示)

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

添加 Darkmode.js 的启用开关

在 Next 的 _config.yml 配置文件添加以下内容,值得一提的是,这里需要注意缩进,第一个 darkmode_js 是在 vendors 栏目下,第二个 darkmode_js 是一个单独的栏目

1
2
3
4
5
6
vendors:
# Darkmode.js
darkmode_js:

darkmode_js:
enable: true

配置 JS 库 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 %}

更改后的源文件就如上所示,其他内容可以根据实际情况自行更改。添加上面的代码后,暗黑模式的切换按钮默认显示在左下角,如果希望切换按钮显示在右下角,可以参考以下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{# Customize darkmode.js - Invokation #}
{%- if theme.darkmode_js.enable %}
<script>
var options = {
bottom: '64px', // default: '32px'
right: '32px', // default: '32px'
left: 'unset', // 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: false // default: true
}
const darkmode = new Darkmode(options);
darkmode.showWidget();
</script>
{%- endif %}

暗黑模式 CSS 样式自定义

实现原理分析

从 Next 8.0 开始,已经原生支持代码块 Dark 主题,直接在 Next 的 _config.xml 文件里配置即可(如下所示):

1
2
3
4
5
6
7
8
9
codeblock:
# Code Highlight theme
# All available themes: https://theme-next.js.org/highlight/
theme:
light: atelier-forest-light
dark: androidstudio
prism:
light: prism
dark: prism-atom-dark

其中 Next 8.3 源文件 themes/next/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 默认会将 darkmode--activated CSS 类添加到 body 标签,可以利用它覆盖暗黑模式默认的 CSS 样式。换句话说,只要将上面的 themes/next/source/css/_colors.styl 里的 CSS 样式添加到 darkmode--activated CSS 类的下面,就可以实现暗黑模式的 CSS 样式自定义,包括代码块颜色自定义切换等。

实现步骤介绍

  • 第一步:创建 themes/next/source/css/_custom/darkmode.styl 源文件,并将以下内容写入到文件里,code 样式用于控制暗黑模式下的代码块颜色显示
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
.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;
}
}

code {
color: #69dbdc;
background: transparent;
}

}
  • 第二步:在 themes/next/source/css/main.styl 文件里引入上面创建的 CSS 文件即可
1
@import '_custom/darkmode.styl';
  • 第三步:在 themes/next/layout/_scripts/vendors.njk 里更改 Darkmode.js 的颜色配置(如下所示),包括设置 mixColor: 'transparent'backgroundColor: 'transparent',否则自定义的暗黑模式 CSS 样式无法达到预期的显示效果
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
{# 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: 'transparent' # default: '#fff'
backgroundColor: 'transparent' # 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 %}

重新构建生成静态文件

Hexo 重新构建生成静态文件后,点击页面上的按钮即可切换暗黑模式

1
2
3
$ hexo clean

$ hexo g -d

最终演示效果

darkmode.gif

常见问题

Darkmode.js 详细配置

Next 7.x 如何手动添加 Darkmode.js

由于 Next 内部开发者的矛盾,导致官方仓库被变更,同时 Next 8.x 版本的代码有很大变化,若希望在 Next 7.x 版本中添加 JS 库 Darkmode.js,可以参考以下博客: