双层色板与主题
样式表与组件用到的每一个颜色都写在 styles/tokens.css 里——唯一的例外是领域的色调对,那由站点注册表以数据的形式提供。这份文件分两层:一层是纸与墨的原始颜料盒,一层是搭在它上面的语义 token;语义层又分两套语境,因为 wiki 有两种页面:供你细读的一列,和供你翻拣的一架。
§1.1第一层:颜料
原始色板是一盒画家的颜料,不随主题变化,统一叫 --p-*。纸类:书架的底「纸」与其卡片面「页」,阅读列的底「素」(比纸再冷一档,连读一小时更不累眼)与其柔和表面「帛」,再加白卡、代码底和公式底。墨类:书架用一套暖墨,阅读列用一套中性墨,各分三档浓淡。装帧:书架的界线、胶囊描边、两根细线。颜料,承载语义的那几个颜色:
--p-zhu: #7d3a3a; /* 朱 · 酒红——书架强调色,站点字标 */
--p-shi: #b6552e; /* 石 · 焦橙——阅读强调色:链接、编号、眉题 */
--p-shi-text: #8f3f1f; /* 石 · 小字档(在石色自己的浅调底上过 AA) */
--p-zhe: #c08a2c; /* 赭 · 赭黄——线条与边框 */
--p-dai: #2a6f6b; /* 黛 · 黛青——内容次级强调色 */
--p-zi: #6b4ec4; /* 紫 · 紫罗兰——「系统」语义 */另配一套夜色供深色版使用:暮色的底、月白的墨,每个颜料再各配一个提亮的夜间对应色。
§1.2两套语境,一盒颜料
第二层才是组件层消费的,它有两副面孔:
| 语境 | token | 底色 | 墨 | 强调色 | 用在哪 |
|---|---|---|---|---|---|
| 阅读列 | --color-* | 素 #fbf9f4 | 中性墨 #1f2024 | 石(焦橙) | 笔记页、全部内容组件、base.css |
| 书架 | --wb-* | 纸 #faf6ec | 暖墨 #2b2622 | 朱(酒红) | 落地页与分类页、wiki 组件、browse.css |
两者之中,阅读列更安静——那是要连读一小时的地方;书架更暖,并且排展示衬线——那是扫一眼、挑一本的地方。页面进入书架语境只需在 body 上挂一个类 wb-root:在它内部,chrome token(--color-bg、--color-accent 等)被重新映射到书架的取值上,于是只写一遍的导航栏在两种底色上都坐得端正;分类原子(类型徽章、状态点、领域 chip)也一样——它们对着 --color-* 书写,在笔记页上读起来就属于阅读列,在导览页上读起来就属于书架。组件层只许消费第二层——base.css、browse.css 和每一个组件都是如此;没有一条规则含裸色值,也没有任何 var() 回退到裸色值。这是这个包的硬纪律。
§2.1站点如何定制身份
覆盖第一层就够了。把颜料换成你自己的,两套语境和整个组件层全部跟着走。每个颜料都是昼夜一对:浅色主题读 --p-shi 与 --p-zhu,深色主题读它们的夜间对应色 --p-shi-n 与 --p-zhu-n——做身份覆盖时两个都设;不设,深色版就沿用默认颜料:
:root {
--p-shi: #b03a48; /* 你的阅读列强调色 */
--p-shi-text: #93303c; /* 小字档要单独压深,理由见下文 */
--p-zhu: #3b4a7a; /* 你的书架强调色与字标色 */
--p-shi-n: #e0919b; /* 夜间对应色,为暮色底提亮 */
--p-zhu-n: #9fb0e4;
}如果你的设计体系本来就有一套色板,把第二层直接重新映射过去也同样是受支持的路径——让 --color-*、--wb-* 指向你自己的变量即可。本园地有意什么都不覆盖:你眼前看到的就是这个包的素面,也正是纸与墨那篇立场笔记为之辩护的那一副面孔。
§2.2对比度是量出来的
每一个文字档的取值,都在它实际所处的每一种底色上按 WCAG AA(无障碍对比度的达标线)验过:小字从 4.5:1 起步;强调色一旦用作小字,就配一个单独压深的文字档(--p-shi-text、--p-zhe-text),因为 12px 的强调色标签往往正坐在强调色自己的浅调底上;淡墨取的是「还读得出淡意」的最深一档——#6a6d74 在阅读底上是 4.9:1,在帛面上仍有 4.5:1;代码底比纸色浅一档,好让语法配色里最淡的一类(注释)也能过 4.5:1;深色版另有一套提亮的取值,对着夜色底逐一量过。这套测量本身也随包发布成工具:scripts/contrast_probe.mjs 用真实浏览器渲染示范站,明暗两主题、两档视口宽度,从像素里采样每段文字脚下的底色,把所有不达标的文字逐条报出来(对比度探针)。改任何一个取值之前,先弄清它坐在哪些底色上。
§2.3浅色才是本体
主题有意不读 prefers-color-scheme(操作系统的明暗偏好):页面绝不可以在读者眼皮底下自己翻转主题。深色只经 [data-theme='dark'] 生效,由站点自己的开关切换(就是本站导航栏右侧那颗日/月按钮;选择存在 localStorage 的 inkstone-theme 键下,由 ThemeInit 内联脚本在首帧绘制前回放,深色读者不会先瞥见一闪米色)。深色不是一键反色,而是手工调制的第二版:暮色的底、月白的墨、重新提亮的颜料——深色是重排的第二版,不是反色。
§2.4字体也住在这一层
一共四套字体栈。--font-display 是书架的脸面——带光学字号轴的衬线(Source Serif 4,汉字配思源宋体),用在版头与书架标题上;本示范站经 @fontsource 自托管这套字,不托管的站点会回退到阅读字体。--font-body 是阅读列的——以 Charter 和 Iowan Old Style 打头的系统衬线栈,系统里没有它们时由展示衬线顶上。--font-ui 是 Inter(汉字配思源黑体),管标题、chrome 与小字。--font-mono 是 Maple Mono CN 的固定字符集子集(ASCII + 制表线字符 + 常用 3500 汉字 + 现有内容全部用字的并集):拉丁字符宽 0.6em,汉字宽 1.2em——一个汉字恰好占两个字符格,中英混排里的制表线图也不会错位。子集配方与重制脚本随包发布(fonts/build_font_subset.py);内容用到覆盖之外的字形时,重跑一遍并把 woff2 一起提交。代码框整个就排在这个子集里。