Files
tamabox/docs/theme-new-sakura.md
T
tamakyi 8941744621 new-sakura:顶栏改半透明磨砂,并立规矩禁止全透明
线上(box.shiroko.one/_/tamakyi)两个现象来自同一处:`--tb-navbar` 是实色,
顶栏那条带(y=20..80)把从右上角长出来的花枝齐刷刷切掉一段。

第一版顺手改成 transparent —— 花枝完整了,但顶栏"消失":导航失去依托,
文字直接压在花纹上。用户当场否掉,要求半透明。

- 顶栏:`rgba(253,246,248,0.72)` / 深色 `rgba(34,26,30,0.72)`,配
  `.uk-navbar-container{backdrop-filter:blur(12px)}`(令牌只能是颜色,模糊写在规则里)。
  0.72 有依据:导航文字 #6d555d 纯底 6.34:1,最坏情况(深花瓣在顶栏后面)压平后 5.08:1。
- 花枝 top -16px → 26px:顶栏半透明后,700~760px 宽度下枝头正好压在「登录」上(截图确认)。
- 手机底栏 #tb-mobile-utils 在 base.css 写死 rgba(255,255,255,.92),粉底上是一条白杠,
  主题里改成同色系 0.92。
- 新增 TestNavbarNotFullyTransparent:拦 `transparent` / `rgba(...,0)` / `#rrggbb00`,
  并说明"这不是审美偏好,是踩过之后立的规矩"。变异验证过(改回 transparent 立即 FAIL)。
  约定同时写进 static/css/themes/_scaffold.css 的令牌说明。
- StaticVersion 20261022b → 20261022c:css 改了不提版本号,浏览器拿着旧样式,
  现象就是"改了但线上没变"。
2026-10-22 16:05:37 +08:00

10 KiB
Raw Blame History

new-sakura(新·樱花):纯 CSS 樱花主题

和已有的 sakura 的区别:sakura 是「粉底 + 网点」的静态配色;new-sakura 把樱花本身 做成了可摆放的装饰层 —— 整朵花、带缺口的花瓣、带枝的花朵树,全部是内联 SVG 的 data:image/svg+xml URI,写在主题 CSS 里。

因此这个主题:

  • 不需要任何图片素材,也不依赖对象存储(static/images/themes/new-sakura/ 是空的);
  • 任意视口缩放都不糊(矢量),DPI 无关;
  • 换花色只改 dev/theme-tools/gen_new_sakura.py 里的一个色值,重跑即得;
  • 没有额外 HTTP 请求 —— SVG 就在 CSS 里。

代价是 CSS 有 54KB(服务端有 gzip,实际传输约 4KB)。主题 CSS 走 StaticVersion 缓存,一次性开销。

结构

static/css/themes/new-sakura.css      ← 生成产物,别手改
dev/theme-tools/gen_new_sakura.py     ← 改这里,重跑
python dev/theme-tools/gen_new_sakura.py

生成器脚本里有三样东西:花形(blossom / petal / branch / pattern)、 每个页面作用域的位置表(SCOPES)、以及配色(LIGHT / DARK)。

每个页面的樱花位置

--tb-deco / --tb-deco-size / --tb-deco-position 三组各 10 槽,必须等长 (TestDecoSlotCount 会逐文件逐声明检查)。

作用域 选择器 构图
global html[data-theme-style="new-sakura"] 右下花枝 + 左上大花 + 两片落瓣
box …[data-page-scope="box"] 右上花枝垂下(细端在外、粗端朝内)+ 左下花与落瓣
question …[data-page-scope="question"] 左下花枝斜穿 + 右上大花 + 落瓣
admin …[data-page-scope="admin"] 左上花枝 + 左侧底部小花(卡片占满宽度,右侧会被盖住)
profile …[data-page-scope="profile"] 右下花枝 + 左侧竖排小花与落瓣
vote …[data-page-scope="vote"] 左上花枝 + 右侧花与落瓣

位置一律「关键字 + 偏移」两值写法(right -24px top -16px)。三值语法里混用 left / bottom 关键字是非法的,整条声明会作废、花瓣静默回到左上角。

窄屏(≤640px)

装饰层全部置 none:卡片占满宽度,左右只剩 16px 边距,枝条放哪儿都会糊在字上。 樱花改由底纹承担 —— @media 里换成加强版 pattern(透明度 ×1.9)并把格子收到 180px; 桌面那套 0.180.34 的透明度在 390px 上实测接近一片纯粉。

试过在「顶栏与卡片之间」那条 35px 的带子里放两朵小樱花:box 页卡片从 y=122 起还行, question / admin 页卡片从 y=110 起就切掉半个,结果是黏在卡片边上的粉色碎块。手机上没有 可靠的留白,就不放装饰层 —— 观感交给配色与底纹。

⚠️ 窄屏覆盖必须重新声明每个作用域选择器:@media 不提升特异性。 作用域块是 html[data-theme-style][data-page-scope="box"](0,2,1),而媒体查询里常见的 html[data-theme-style](0,1,1)根本压不住它 —— 表现是「手机上装饰层没关掉,桌面版照样铺开」。 深色作用域块更是 0,3,1,还得再补一条 [data-theme="dark"][data-theme-style][data-page-scope]。 TestNarrowMediaOverridesScopedDeco 会在这里把关:外层每一处非 none 的 --tb-deco, 媒体查询里都要求有同属性名、属性数不少于它的选择器再声明一次。

深色

  • 花瓣换成更亮一档的粉(#f0a0b8),枝条提亮到能看见;
  • 底纹 --tb-page-pattern: none:浅粉花瓣压在深底上会变成一层噪点;
  • 整页背景改深色渐变(不用纯色,避免大面积死黑)。

深色块必须写成 html[data-theme="dark"][data-theme-style="new-sakura"](三重选择器), 只写浅色块会被同特异性的作用域块盖掉。

顶栏与手机底栏

顶栏走磨砂玻璃,不是实色也不是全透明:

--tb-navbar: rgba(253, 246, 248, 0.72);          /* 亮色;深色 rgba(34, 26, 30, 0.72) */
html[data-theme-style="new-sakura"] .uk-navbar-container:not(.uk-navbar-transparent) {
    -webkit-backdrop-filter: blur(12px);
    backdrop-filter: blur(12px);
}

三种写法的实测结论:

写法 现象
实色 #fdf6f8 花枝经过顶栏时被齐刷刷切掉一段,像被裁过
transparent 花枝完整了,但顶栏"消失":导航没有依托,文字直接压在花纹上
rgba(...,0.72) + blur(12px) 花枝透过来但被模糊成柔光,顶栏仍是一块可辨认的面

0.72 是怎么定的:导航文字 #6d555d 压在顶栏上,纯底色 6.34:1;最坏情况(深花瓣正好在顶栏后面) 压平后 5.08:1,仍过 AA。再往下调透明度就会掉到 4.5 以下。

TestNavbarNotFullyTransparent 会拦住 --tb-navbar: transparent(以及 rgba(...,0)、 #rrggbb00)—— 这条不是审美偏好,是把上面第二种写法踩过之后立的规矩。

手机底栏(#tb-mobile-utils)在 base.css 里写死 rgba(255,255,255,.92),压在粉底上是 一条白杠;主题里按同一思路改成 rgba(253,246,248,.92) / rgba(34,26,30,.92)。

另外 box 作用域的花枝从 top -16px 下移到 top 26px:顶栏半透明后,700~760px 宽度下 枝头正好压在「登录」上(实测截图确认)。顶栏高 60 + 外边距 20,26px 起笔即落在顶栏下沿之上, 宽屏仍是"从右上角长出来"的观感。

配色与对比度

令牌 亮色 深色 说明
--tb-bg #fdf6f8 #221a1e 纯色,不用渐变(整页色感一致)
--tb-surface #ffffff #2c2227 卡片
--tb-text #3a2c31 (12.4:1) #f3e6ea (14.0:1)
--tb-text-secondary #6d555d (6.3:1) #c9aeb8 (8.3:1)
--tb-text-muted #77626a (5.3:1) #ab9099 (5.8:1) 踩 AA 下限
--tb-primary #b8436a (4.9:1) #ff93b4 (8.2:1) 原候选 #c14a72 只有 4.39:1,压深
--tb-on-primary #ffffff (5.2:1) #1b1014 (8.9:1) 主色按钮上的字

素材包(可选,已传到对象存储)

主题线上不需要任何素材:樱花是内联矢量。但同一个花形也导出成了位图, 放在对象存储上备用(themes/new-sakura/,共 7 个对象):

键 内容
new-sakura.css 主题本体(备份,便于分发)
branch-right.webp / branch-left.webp 花枝 840×640 透明底(互为镜像)
blossom.webp 单朵樱花 400×400 透明底
petal.webp 带缺口的花瓣 240×336 透明底
pattern.webp 平铺底纹 600×600 透明底
INSTALL.txt 包内说明

重新导出 / 上传(--upload 会一起传 CSS、位图和生成的 INSTALL.txt):

python dev/theme-tools/export_assets.py            # 只导出到 outputs/sakura-assets
python dev/theme-tools/export_assets.py --upload   # 导出并上传,读 data/r2.txt

data/r2.txt 是部署凭据(image_endpoint / image_access_id / image_access_secret / image_bucket / image_bucket_cdn_host),不进版本库(.gitignore 里的 /data/)。 image_bucket_cdn_host 与 conf/app.ini 同名同义:只写主机名,不带 https:// 和路径; 没有它时 INSTALL.txt 里的公开地址会写成占位符。

缓存策略:位图 max-age=86400、CSS 镜像 300、INSTALL.txt 60。 这些键都不带内容版本,所以刻意不用 immutable —— 否则重新导出后,浏览器与 CDN 一年内拿到的都还是旧图。想要一年长缓存,得把内容哈希写进文件名(CSS 里的地址跟着换)。

⚠️ 若某个键曾经以 immutable 传过(本主题第一版就是这样),CDN 会一直给旧副本, 改完必须去控制台按 URL 清一次缓存,光重传没用。

位图版(引用对象存储)

桶绑了自定义域 r2.337845818.best(实测匿名 GET 200、image/webp、大小一致), 所以可以把 CSS 从内联切到位图:

python dev/theme-tools/gen_new_sakura.py \
  --asset-base https://r2.337845818.best/themes/new-sakura \
  --out static/css/themes/new-sakura.css
版本 CSS gzip 后 额外请求 清晰度
内联 SVG(默认) 53.8KB 4.0KB 0 矢量,任意 DPR
位图 11.8KB 2.8KB 5 个 webp,共 48.9KB 2 倍图

服务端挂了 gzip(internal/route/gzip.go),所以内联版总传输 4.0KB,比位图版的 2.8 + 48.9 = 51.7KB 小一个数量级 —— 换位图省不了流量,只是把开销从 CSS 挪到图片。 位图版唯一正当的理由是素材要单独复用(分享卡、海报、其它系统)。

⚠️ 直接连桶的 S3 endpoint(*.r2.cloudflarestorage.com)会 403,只有自定义域/r2.dev 可匿名读。 切之前先 curl -I 验一下前缀;切完 go build 部署,否则 embed 里还是旧的。

为什么不用主题生成器出图

生成器的装饰层只支持「图片素材」(导出时打进 zip 或传对象存储),没有内联 SVG 图层。 要把樱花做成可摆放的图层,只能在设计上二选一:

  1. 生成图片素材(花瓣 PNG/WebP)→ 可以用生成器、可以放 S3,但会有位图缩放、额外请求;
  2. 内联 SVG 写进 CSS → 零素材、任意缩放不糊,但生成器管不到。

new-sakura 选 2,因为「用 CSS 做樱花」本身就是这个主题的诉求。 生成器仍然可以用来预览它:?demo=1&fresh=1 起画板,把 new-sakura.css 注入即可。

怎么验证

go test ./internal/theme          # 10 槽等长、深浅块成对、必需令牌齐全、窄屏覆盖特异性

视觉自检用项目真实页面快照:

TEST_PREVIEW=1 go test ./templates -run TestGenPreview
python dev/theme-builder/serve.py
# 打开 outputs/preview-box-light.html,DevTools 里给 <html> 加
#   data-theme-style="new-sakura"  data-page-scope="box"

上线

  1. conf/app.ini 的 [theme] available 加上 new-sakura(不改就「设置页看不到」,现象和部署没生效一样);
  2. 重新 go build —— 主题 CSS 是编译期 embed,只重启不重编不会变;
  3. 箱主设置页 → 账号 → 外观,选择「新·樱花」。