记账小助手
命令行 + Web 双端的个人记账工具,CSV 导入、按月统计。
Node.js · SQLite · Vue
命令行 + Web 双端的个人记账工具,CSV 导入、按月统计。
极简番茄钟,支持白噪音和每日专注统计。
把一段 Markdown 渲染成适合发朋友圈的长图。
一键收藏网页到看板,自动提取正文与阅读时长。
给博客加暗色模式,是很多人做个人站时的头一个“小需求”。看起来只是换个颜色,但真做起来会遇到几个问题:要不要跟随系统?用户手动切换后怎么记住?刷新时为什么会闪一下白?这篇笔记把我试过的三种方案整理一下。
本文为演示内容,用于展示博客的排版、代码高亮与暗色模式效果。右上角的按钮就是本文方案二 + 方案三的实际效果。
省事的做法是把颜色都定义成 CSS 变量,然后在 prefers-color-scheme 媒体查询里重新赋值。不需要一行 JavaScript:
/* 亮色为默认值 */
:root {
--bg: #FAFAF7;
--ink: #1B2130;
--radius: 14px;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #0E1117;
--ink: #E5E9F0;
}
}
body { background: var(--bg); color: var(--ink); }缺点也很明显:用户没法单独给这个网站选择亮色或暗色。
把主题挂到 <html data-theme="dark"> 上,CSS 用属性选择器覆盖变量;切换时写入 localStorage。注意存储在隐私模式下可能抛异常,要包一层 try/catch:
const KEY = 'theme';
// 读取用户上次的选择,没有就跟随系统
function getTheme() {
let saved = null;
try { saved = localStorage.getItem(KEY); } catch (e) {}
if (saved === 'light' || saved === 'dark') return saved;
return matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
function toggleTheme() {
const next = document.documentElement.dataset.theme === 'dark' ? 'light' : 'dark';
document.documentElement.dataset.theme = next;
try { localStorage.setItem(KEY, next); } catch (e) {}
return next;
}如果切换逻辑写在页面底部的脚本里,暗色用户刷新时会先看到一帧白色背景。解决办法是把读取主题的几行代码内联到 <head> 里、在 CSS 之前执行:
<script>
// 阻塞执行,但只有几行,几乎没有性能影响
(function () {
var t = null;
try { t = localStorage.getItem('theme'); } catch (e) {}
if (t !== 'light' && t !== 'dark') {
t = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
}
document.documentElement.setAttribute('data-theme', t);
})();
</script>另外,图片和图表也要考虑暗色:SVG 图标用 currentColor,截图类图片可以加一点 filter: brightness(.9)。
完整示例就是你现在看到的这个页面,可以打开开发者工具看看源码。