这个站的视觉部分一共两个文件:一个 CSS(未压缩约 12 KB)和一个 JS(约 6 KB)。没有框架、没有构建工具、没有网络字体。这篇记录一下其中两个值得说的点。

一、深色模式:CSS 变量 + data-theme

把所有颜色抽成变量,放在 :root 和 [data-theme="dark"] 两套里:

:root {
  --bg: #ffffff;
  --text: #1b1f24;
  --accent: #2f6feb;
}

[data-theme="dark"] {
  --bg: #0e1116;
  --text: #e6edf3;
  --accent: #6ea8fe;
}

页面里所有颜色都引用变量(color: var(--text)),于是切换主题只需要改 html 上的一个属性:

document.documentElement.setAttribute('data-theme', next);
localStorage.setItem('theme', next);

好处是深色模式不需要写第二套 CSS,改配色也只改上面那十几行。顺带一提,深色模式不是把颜色取反就行:#000 配纯白文字会太刺眼,正文用 #e6edf3 更舒服;蓝色在深色背景上要提亮,不然会显得脏。

二、防止深色模式闪白屏

如果只在 JS 里读 localStorage 再设主题,会遇到一个经典问题:用户选了深色,每次打开还是先闪一下白屏。原因是 CSS 已经渲染了,JS 还没执行。

解决办法是在 <head> 里、任何样式生效之前,插入一段同步执行的内联脚本:

<script>
(function(){
  var t = localStorage.getItem('theme');
  if (!t) t = matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
  document.documentElement.setAttribute('data-theme', t);
})();
</script>

因为它同步执行,浏览器后续绘制就已经带上正确的 data-theme,不会闪。这也是为什么主题初始化脚本必须内联、不能用 defer。

另外,没手动设置过的用户会跟随系统(prefers-color-scheme),一次设置之后以手动选择为准。

三、搜索为什么不需要后端

全文搜索跑在浏览器里。构建时把所有文章的标题、摘要、标签和正文前 800 字导出一个 index.json:

[
 {
  "title": "浅色深色都好看:一次主题与性能的小改造",
  "url": "posts/2026-09-28-theme-and-performance.html",
  "date": "2026-09-28",
  "tags": ["前端", "CSS"],
  "summary": "……",
  "text": "……"
 }
]

搜索页的 JS 把它 fetch 下来,在内存里做关键词匹配,支持空格分隔的多个关键词(全部命中才算匹配),并把命中的文字用 <mark> 高亮。

这个方案的上限是几千篇文章,再往上索引文件会大到不值得下载。真到了那个量级,再换生成时预建倒排索引的方案也不迟——现在为三年后才可能出现的问题写代码,是过度设计。

fetch 受同源策略限制,所以搜索必须通过 http 访问。用 file:// 直接打开 HTML 文件时搜索会失效,本地预览请用 python3 build.py --serve。

四、其他几个小决定

  • 不用网络字体。用系统字体栈(-apple-system / PingFang SC / Microsoft YaHei),中英文都好看,省掉几百 KB 的下载和字体闪烁。
  • 代码块不引高亮库。语法高亮库动辄几十 KB,本站只给代码块加了语言标签和复制按钮,性价比更高。
  • IntersectionObserver 做目录高亮。比监听 scroll 事件省性能,也不用自己算节流。
  • 图片统一 loading="lazy"。首屏之外的图片不参与首屏加载。

五、改配色速查

想换一套风格,只改 static/style.css 顶部这十来个变量就够:

变量作用
--bg / --surface页面背景 / 卡片背景
--text / --text-soft正文 / 次要文字
--accent链接、标签、按钮的强调色
--border分隔线和描边
--radius圆角大小
--maxw正文最大宽度(现在 780px,适合中文阅读)

改完重新构建,浏览器强制刷新一下(Ctrl/Cmd + Shift + R)就能看到效果。

小结

小站点最大的优势不是「快」,而是每一行代码你都知道它为什么在那儿。出问题的时候不用查半天框架文档,出错也就那几个文件。这个优势在站点变复杂之前,一直有效。