惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

F
Full Disclosure
WordPress大学
WordPress大学
小众软件
小众软件
Cloudbric
Cloudbric
AWS News Blog
AWS News Blog
腾讯CDC
量子位
人人都是产品经理
人人都是产品经理
大猫的无限游戏
大猫的无限游戏
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
V
Vulnerabilities – Threatpost
Scott Helme
Scott Helme
Hugging Face - Blog
Hugging Face - Blog
博客园_首页
C
CXSECURITY Database RSS Feed - CXSecurity.com
The Hacker News
The Hacker News
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
IT之家
IT之家
Jina AI
Jina AI
Attack and Defense Labs
Attack and Defense Labs
S
SegmentFault 最新的问题
Simon Willison's Weblog
Simon Willison's Weblog
The Cloudflare Blog
阮一峰的网络日志
阮一峰的网络日志
T
Tailwind CSS Blog
Last Week in AI
Last Week in AI
博客园 - 【当耐特】
Google Online Security Blog
Google Online Security Blog
美团技术团队
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
V
Visual Studio Blog
罗磊的独立博客
L
LINUX DO - 最新话题
博客园 - Franky
博客园 - 叶小钗
Apple Machine Learning Research
Apple Machine Learning Research
The Last Watchdog
The Last Watchdog
J
Java Code Geeks
AI
AI
C
Cisco Blogs
酷 壳 – CoolShell
酷 壳 – CoolShell
C
Cyber Attacks, Cyber Crime and Cyber Security
Cisco Talos Blog
Cisco Talos Blog
博客园 - 三生石上(FineUI控件)
雷峰网
雷峰网
Help Net Security
Help Net Security
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
云风的 BLOG
云风的 BLOG
I
Intezer
S
Securelist

翰林的小站

Bilibili 自建视频云生态观察 2025:拿着过去的碎片,到远方去 Bad Apple:ALAC 音乐完整性验证与速查指南 年轻人的第一个包:不太严谨的 AOSC OS 贡献指南 2024:在变与不变之中做一颗不动的石头 关于浏览器通知推送(Web Push API)的那些事 HTP 笑传:扔掉 UDP,试试并不特殊的低精度时间同步 切割,与世界上的另一个我 时间线之外的 Kench BF-0505 官方驱动无法在高 DPI 下扫描 TIFF 文件的解决方案 Migrate Dream! It's MyHexo!!!!! 验证:所幸,七牛云还是能「防护」住 XFF 的(附后续) 从山西联通到组播IP:七牛云的奇怪视角(附分析和后日谈) 消失的 2023 B站百大报告 2023:走在参差的影子之下 Hackergame Writeup 2023 : A Newbie Perspective 连夜分析,探寻B站2022年度百大的版本答案 2022:不为所动,做最业余的年度报告 对于谷歌翻译大陆版「引导页」行为的观测(2022年9月底)
博客现已支持手动切换深浅色模式
abc1763613206 · 2024-09-04 · via 翰林的小站

博客现已支持手动切换深浅色模式

从现在开始,博客已经支持手动切换深浅色模式了。仅需点击页面左下角的最后一个按钮(移动端可拉到最下方点「🔁 切换主题」),或是试试点击这几个链接:深色模式,浅色模式,跟随系统

本来这里打了一长串字想解释来龙去脉的,直到后来我发现 hexo-theme-stellar 已有了一个比较粗暴的实现。所以这次仅提供修改时的流水账,供其他人魔改参考。
源码可参见 fa8e5d64277bc6 .

样式注入

定义 theme.style.darkmode == 'auto-switch' 为开关。
整体上通过写入 data-theme 选择器来实现,因为当前的逻辑是一启动就向 html 注入 data 属性,索性把 auto 也复制了一份情况。

source/css/_defines/theme.styl
1
2
3
4
5
6
if hexo-config('style.darkmode') == 'auto-switch'
:root[data-theme="dark"]
set_darkmode()
:root[data-theme="auto"]
@media (prefers-color-scheme: dark)
set_darkmode()

评论区组件仅测试了 Waline,通过变量定义配色板非常方便。

source/css/_plugins/comments/waline.styl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
if hexo-config('style.darkmode') == 'auto-switch'
:root[data-theme="dark"] .wl-count
padding: .375em;
font-weight: bold;
font-size: 1.25em;
color: #fff;

:root[data-theme="dark"] .cmt-body.waline
--waline-white: #000;
--waline-light-grey: #666;
--waline-dark-grey: #999;

--waline-color: #fff;
--waline-bg-color: #2b2f33b2;
--waline-bg-color-light: #272727;
--waline-border-color: #333;
--waline-disable-bg-color: #444;
--waline-disable-color: #272727;

--waline-bq-color: #272727;

--waline-info-bg-color: #272727;
--waline-info-color: #666;

修改逻辑

修改了配置中 footer 的部分,仅需配置三个状态下的图标,方便不想把图标放在最后一位的用户。

_config.yml
1
2
3
4
5
6
footer:
social:
darkmode:
auto: '<img no-lazy width="24" height="24" src="/images/sun-moon.svg"/>'
light: '<img no-lazy width="24" height="24" src="/images/sun-fill.svg"/>'
dark: '<img no-lazy width="24" height="24" src="/images/moon-fill.svg"/>'

预处理后的按钮直接绑定 switchTheme() 事件。

layout/components/sidebar/sidebar.jsx
1
2
3
4
5
6
7
<div className="darkmode-switch"
id="darkmode-switch-light"
title={__('message.theme_switched.light')}
data-on-click="switchTheme()"
>
{parse(item.light)}
</div>

为了防止页面加载闪屏,在加载 main.css 之前,就需要做好属性注入。

layout/components/head.jsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
const ImportDarkMode = (props) => {
const {theme} = props
const DarkModePreset = `
const themeModeList = ['light', 'dark', 'auto'];
var ThemeChange = (theme) => {
if(theme == null){
theme = 'auto';
}
document.documentElement.setAttribute('data-theme', theme)
window.localStorage.setItem('Stellaris.theme', theme);
}
ThemeChange(window.localStorage.getItem('Stellaris.theme'));
`
if (theme.style.darkmode == 'auto-switch') {
return <script type="text/javascript" data-no-instant="true" dangerouslySetInnerHTML={{__html: DarkModePreset}}/>
} else {
return <></>;
}
}


<ImportDarkMode {...props}/>
<ImportCSS {...props}/>

动态按钮

本来想着动态插拔 class 属性,晚上又突然想到可以使用 data-theme 来实现。
按照约定好的顺序,依次在当前状态下展示下一个按钮即可。

source/css/_components/darkmode.styl
1
2
3
4
5
6
7
8
9
.darkmode-switch
display: none
cursor: pointer
:root[data-theme="dark"] #darkmode-switch-auto
display: inline-block
:root[data-theme="auto"] #darkmode-switch-light
display: inline-block
:root[data-theme="light"] #darkmode-switch-dark
display: inline-block

在页尾再加个监听 prefers-color-scheme 的事件,以便在系统切换时自动切换。最后把前文绑定的函数实现一下即可。

layout/components/scripts.jsx
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
const ImportDarkModeListener = (props) => {
const {theme, __} = props
const DarkModeListener = `
const applyTheme = (theme) => {
document.documentElement.setAttribute('data-theme', theme);
window.localStorage.setItem('Stellaris.theme', theme);
const messages = {
light: '${__('message.theme_switched.light')}',
dark: '${__('message.theme_switched.dark')}',
auto: '${__('message.theme_switched.auto')}',
}
hud?.toast?.(messages[theme]);
}
const switchTheme = () => {
const currentTheme = document.documentElement.getAttribute('data-theme');
let nextTheme = themeModeList[(themeModeList.indexOf(currentTheme) + 1) % themeModeList.length];
applyTheme(nextTheme);
}
var OSTheme = window.matchMedia('(prefers-color-scheme: dark)');
OSTheme.addEventListener('change', e => {
if (document.documentElement.getAttribute('data-theme') === 'auto') {
ThemeChange('auto');
}
})
`
if (theme.style.darkmode == 'auto-switch') {
return <script type="text/javascript" data-no-instant="true" dangerouslySetInnerHTML={{__html: DarkModeListener}}/>
} else {
return <></>;
}
}