浅色改为暖纸底 + 纸纹底 + 移动端分类胶囊条

浅色配色(global.css,暗色未动)
- 纯白底在屏幕上偏刺眼、大面积纯色没有视觉落点,整套浅色 token
  压到 L*≈96 并给暖黄彩度(oklch hue 84),墨色换成暖褐而非纯黑
- background #f8f3e9 / surface-subtle #f4eee3 / card #fcf8f0(比页面底亮,
  靠明度差拉层次)/ foreground #221d18 / border #dfd9ce
- 对比度仍留足:正文 15:1、content-secondary 7.5:1、muted-foreground 5.3:1、
  主色链接 4.9:1(AA 要求 4.5:1)
- secondary / sidebar / popover 等原来偏中性的 token 一并转暖,避免冷暖打架

纸纹底
- --paper-noise 用内联 SVG feTurbulence 分形噪声,无需图片文件;
  feColorMatrix saturate=0 去饱和得到带随机 alpha 的灰颗粒,
  因此不需要 mix-blend-mode 就能亮暗通用
- body::before 铺成 position:fixed 整屏颗粒,z-index:1(压在正文上、
  页眉 z-50 / 菜单 z-60 之下),pointer-events:none
- 颗粒浓度:亮色 0.2 / 暗色 0.22。实测亮度标准差 0.05→0.7、0.2→1.9、
  0.3→2.9(0=完全平整),选 2 左右这个「看得出是纸但不觉得脏」的档位
- 顺带让 backdrop-filter 有细节可模糊,此前纯色底上磨砂等于不存在

移动端分类胶囊条(article-list.tsx + sidebar.tsx)
- 移动端侧栏被排在文章列表下面(实测首篇 y=999、侧栏 y=3212),
  分类筛选基本摸不到;现在列表顶部多一条吸附胶囊条
- 复用同一份 categories / activeCategory / handleCategoryChange,不写第二套;
  末尾胶囊在「分类 / 标签」间切换;两端渐隐提示可横向滑;滚动条藏掉
- 把当前项自动滚到中间,只操作这条横向容器,不动页面纵向位置
- sidebar.tsx 的分类/标签块加 hidden lg:block,避免同页出现两份

其他
- 新增 --header-h: 69px(页眉实测高度),移动端菜单面板和吸附胶囊条
  都改用它定位,不再各处硬编码 69/76
- README 补「浅色配色」「纸纹底」「移动端分类胶囊条」三节

验证(headless Chrome 131)
- 390px:胶囊条可见、侧栏两块 display:none;点「思考」→ ?category=思考、
  列表 10→4 条、当前项高亮;切到标签模式列出 35 个标签;无横向溢出
- 1280px:胶囊条隐藏、侧栏分类恢复显示(display:block)
- 亮/暗两套截图正常,书架、文章页均无异常
This commit is contained in:
dsh
2026-09-15 09:37:14 +08:00
parent 9d9f87a013
commit 5532c35064
5 changed files with 244 additions and 27 deletions
+69 -21
View File
@@ -14,27 +14,37 @@
* 参考:0=红 25=朱红 200=青 250=蓝绿 345=粉
*/
--content-delay: 150ms;
--background: oklch(0.994 0.002 85); /* 极淡暖白纸感 */
--foreground: oklch(0.15 0 0);
--surface-subtle: oklch(0.982 0.003 85); /* 区块浅底,替代 scattered muted/30 */
--paper-warm: oklch(0.98 0.008 85); /* 专题笔记背景:暖米色,致敬纸感 */
--card: oklch(0.998 0.002 85);
--card-foreground: oklch(0.15 0 0);
--popover: oklch(1 0 0);
--popover-foreground: oklch(0.15 0 0);
/* 固定页眉的实际高度(site-header 的 py-4 + 32px 头像 + 1px 边框)。
移动端菜单、吸附的分类胶囊条都靠它定位,改页眉高度时同步改这里。 */
--header-h: 69px;
/*
* 浅色模式 = 暖纸底,不用亮白。
* 纯白底(L*≈99)在屏幕上偏刺眼,而且大面积纯色没有视觉落点。
* 这里整体压到 L*≈96 并给一点暖黄彩度(hue 84 ≈ 米黄),
* 墨色也换成暖褐而非纯黑 —— 对比度仍在 15:1,远高于 WCAG AA 的 4.5:1。
* 换色时记得同步 .dark 之外这几个派生 token。
*/
--background: oklch(0.964 0.014 84); /* 暖纸底 #f8f3e9 */
--foreground: oklch(0.235 0.013 68); /* 暖墨 #221d18 */
--surface-subtle: oklch(0.952 0.016 84); /* 区块浅底 #f4eee3 */
--paper-warm: oklch(0.958 0.022 80); /* 专题笔记背景 #f9f0e1 */
--card: oklch(0.98 0.011 84); /* 卡片比页面底更亮一点,才有层次 #fcf8f0 */
--card-foreground: oklch(0.235 0.013 68);
--popover: oklch(0.984 0.01 84);
--popover-foreground: oklch(0.235 0.013 68);
--primary: oklch(0.55 0.22 var(--primary-hue, 25));
--primary-foreground: oklch(0.995 0 0);
--secondary: oklch(0.97 0.005 var(--primary-hue, 25)); /* 次要按钮/可交互面,略暖 */
--secondary-foreground: oklch(0.15 0 0);
--muted: oklch(0.96 0.003 85); /* 静态背景:placeholder、禁用区 */
--muted-foreground: oklch(0.45 0 0); /* 元信息:日期、标签、placeholder */
--content-secondary: oklch(0.36 0 0); /* 仍要读的内容:摘要、引用、预览正文 */
--secondary: oklch(0.938 0.016 84); /* 次要按钮/可交互面 #f0eadf */
--secondary-foreground: oklch(0.235 0.013 68);
--muted: oklch(0.93 0.014 84); /* 静态背景:placeholder、禁用区 #ece7de */
--muted-foreground: oklch(0.505 0.012 70); /* 元信息:日期、标签、placeholder,5.3:1 */
--content-secondary: oklch(0.425 0.012 70); /* 仍要读的内容:摘要、引用、预览正文,7.5:1 */
--accent: oklch(0.55 0.22 var(--primary-hue, 25));
--accent-foreground: oklch(0.995 0 0);
--destructive: oklch(0.577 0.245 27.325);
--destructive-foreground: oklch(0.577 0.245 27.325);
--border: oklch(0.92 0.003 85);
--input: oklch(0.92 0.003 85);
--border: oklch(0.888 0.016 84);
--input: oklch(0.888 0.016 84);
--ring: oklch(0.55 0.22 var(--primary-hue, 25));
--status-positive-bg: oklch(0.93 0.04 155);
--status-positive-fg: oklch(0.42 0.12 155);
@@ -48,6 +58,14 @@
--chart-4: oklch(0.828 0.189 84.429);
--chart-5: oklch(0.769 0.188 70.08);
--radius: 0.5rem;
/*
* 纸纹底:内联 SVG 的 feTurbulence 分形噪声(无需图片文件)。
* baseFrequency 越大颗粒越细,stitchTiles 保证平铺无接缝。
* feColorMatrix saturate=0 把彩色噪点去饱和,得到带随机 alpha 的灰颗粒,
* 所以不需要 mix-blend-mode 也亮暗通用。
*/
--paper-noise: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
--paper-noise-opacity: 0.2;
/*
* 磨砂玻璃 token —— 只给「浮在内容上方、面积不大」的元素用
* (移动端菜单、页眉、搜索面板…)。不要给文章卡片大面积用,
@@ -58,13 +76,13 @@
--glass-border: color-mix(in oklch, var(--border) 75%, transparent);
--glass-blur: 14px;
--glass-saturate: 1.5;
--sidebar: oklch(0.985 0 0);
--sidebar-foreground: oklch(0.145 0 0);
--sidebar: oklch(0.968 0.012 84);
--sidebar-foreground: oklch(0.235 0.013 68);
--sidebar-primary: oklch(0.55 0.22 var(--primary-hue, 25));
--sidebar-primary-foreground: oklch(0.985 0 0);
--sidebar-accent: oklch(0.97 0 0);
--sidebar-accent-foreground: oklch(0.205 0 0);
--sidebar-border: oklch(0.922 0 0);
--sidebar-primary-foreground: oklch(0.995 0 0);
--sidebar-accent: oklch(0.93 0.014 84);
--sidebar-accent-foreground: oklch(0.235 0.013 68);
--sidebar-border: oklch(0.888 0.016 84);
--sidebar-ring: oklch(0.55 0.22 var(--primary-hue, 25));
--admonitions-color-tip: oklch(0.62 0.16 180);
--admonitions-color-note: oklch(0.62 0.16 250);
@@ -135,6 +153,8 @@
--math-color: oklch(0.90 0.008 250);
--math-display-color: oklch(0.94 0.008 250);
--math-display-shadow: 0 1px 0 oklch(0.08 0 0 / 0.18);
/* 暗色下颗粒要更明显一点才看得出来 */
--paper-noise-opacity: 0.22;
}
@theme inline {
@@ -230,6 +250,34 @@ html {
scroll-behavior: auto;
}
/*
* 纸纹底:整屏一层极淡的颗粒。
* - position: fixed 让它不随内容滚动,像纸在屏幕后面而不是印在内容上
* - z-index: 1 压在正文之上、页眉(z-50)/菜单(z-60) 之下;不透明度只有几个百分点,
* 等效于全局加了一层胶片颗粒
* - pointer-events: none 必须留,否则整页点不动
* - 不支持 backdrop-filter 的老浏览器不受影响,它只是背景图
*/
body::before {
content: "";
position: fixed;
inset: 0;
z-index: 1;
pointer-events: none;
background-image: var(--paper-noise);
background-repeat: repeat;
opacity: var(--paper-noise-opacity);
}
/* 横向滚动的胶囊条要藏掉滚动条,但保留键盘/触摸滚动能力 */
.no-scrollbar {
scrollbar-width: none;
-ms-overflow-style: none;
}
.no-scrollbar::-webkit-scrollbar {
display: none;
}
html:focus-within {
scroll-behavior: smooth;
}