# 主题(箱主个性化)(长版明细) ## 主题(箱主个性化) - 三个注入点:`/_/{domain}/*` → `question.Pager` 按 `pageUser.Theme`;`/user/*` → `internal/context` Contexter 按 `c.User.Theme`(`isThemeScope()` 只认 `/user` 与 `/user/`);`/vote/{token}` → `route/vote.Page` 按发布者 `owner.Theme`。都看箱主/发布者,不看访客。全站页(`/`、`/explore`、`/login`)不主题化。 - 投票页**语言**也跟发布者:`applyOwnerLocale(data, owner)`(与主题同一函数),必须在任何 i18n 取词之前调用。 - 一套主题 = `static/css/themes/.css`,**只覆盖令牌**,不碰布局。`static/fs.go` 已嵌整个 `themes/` 目录。 - 主题显示名:模板用 `{{ themeName .LangCode .Slug }}` → `theme.DisplayName`,i18n 没登记 `theme.name.` 时**回退成 slug**。⚠️ 别在模板里直接 `{{t .LangCode (printf "theme.name.%s" .Slug)}}`: `i18n.T` 缺词条返回 key 本身,设置页就会显示 `theme.name.test01`(用户报过)。 - ⚠️ **`[theme] available` 是硬白名单,启动时读一次**:css 发布了但没登记,设置页看不到,现象同「部署没生效」。 排查:`curl /static/css/themes/.css` 200 = 文件在(没登记);404 = 旧二进制。 - ⚠️ 主题 css **必须成对写**:`html[data-theme-style="x"]`(0,1,1) + `html[data-theme="dark"][data-theme-style="x"]`(0,2,1)。 `TestThemeCSSComplete` 查两个选择器 + 10 个颜色令牌。 - ⚠️ **按页面作用域**:`internal/context.pageScope()` → ``,取值 `box`/`question`/`admin`(/user/questions,/user/votes*)/`profile`/`vote`。深色作用域覆盖必须**三重选择器**, 否则被浅色作用域块(同特异性、写在后面)盖掉。 - ⚠️ **装饰层固定 10 槽**(base.css 12 层 = pattern1 + deco10 + image1),三组 `--tb-deco/-size/-position` 必须等长。`TestDecoSlotCount` 逐文件逐声明检查(只扫 embed 到的文件)。 - 位置一律两值 `calc(0%|50%|100% ± N)`(百分比相对「容器 − 图片」)。**别用 left/bottom 关键字混搭**: 三值语法非法时整条声明作废 → 图层静默回左上。 - 尺寸想随视口缩用 `clamp`,**不要写死 px**:`auto clamp(min(calc(100vh - 24px), 231px), 46.67vh, 420px)`。 内层 `min()` 是兜底 —— 屏幕小到连下限都放不下时让位给视口。宽幅素材只能按宽度缩(`vw`), 按高度缩的话宽度按比例涨,窄屏照样裁。 - ⚠️ **UIkit 3.3.3 主色是编译期常量 `#1e87f0`**,令牌注入不进去。base.css 末尾按组件映射(a/uk-link、 uk-button-primary、checkbox/radio、input:focus、uk-tab active、`.uk-progress`、`.uk-label:not(...)`)。 - 令牌 `--tb-navbar`(顶栏底色,默认 `var(--tb-surface)`):页面底色偏彩时主题必须覆盖。 ⚠️ **顶栏只能半透明,不能全透明**(2026-10-22 用户明确要求):装饰层从角落长出来时实色顶栏会把 花枝切一段;但改成 `transparent` 顶栏就"消失"了,导航失去依托、文字压在花纹上。正解是 `rgba(bg, 0.72)` + `.uk-navbar-container{backdrop-filter: blur(12px)}`(模糊只能写在规则里, 令牌只是颜色)。`TestNavbarNotFullyTransparent` 拦 `transparent` / `rgba(...,0)` / `#rrggbb00`。 同理 `#tb-mobile-utils` 在 base.css 里写死 `rgba(255,255,255,.92)`,彩色主题要自己调成同色系。 - ⚠️ 装饰层会穿过顶栏区域时,`top` 别停在 0~nav 高度内:改半透明后枝头会压到「登录」上 (700~760px 宽度实测),按顶栏高度(60 + margin 20)把 `top` 下移。 - 静态资源版本号统一 `conf.StaticVersion`;**图片不走这个缓存键**(`max-age=86400`),换图要给 URL 带 `?v=`。 - 整页背景 `--tb-page-image`(cover)/ `--tb-page-pattern`(平铺,`-size` 控尺寸)/ `--tb-page-position` (焦点,默认 `var(--tb-page-position, center center)`,旧主题不写也不坏)。底色用**纯色**别用渐变; 图案 ≥24px、透明度 ≤0.06。 - ⚠️ **多背景层不能塞变量列表**:变量自身是逗号列表会让层数与 size/position 错位。多张装饰用固定槽位。 - 装饰摆位:**贴边、成组、避开页脚**;四角各摆一个会读成贴纸墙纸;页脚文案右对齐 → 右下角不能放人物。 `--tb-deco` 是 fixed 视口层,贴边插画别放进 `cover` 背景图(必裁边)。 - 主题视觉的**结构**比摆位重要:通行做法是「整屏场景插画 + UI 悬浮其上」(蔚蓝档案 JP)。 白底留白里摆人物,无论多大都读成贴纸;卡片/顶栏配半透明白 + `backdrop-filter` 才有"浮在画面上"的关系。 - 素材放 `static/images/themes//`(embed 已含 `images/themes`,子目录自动覆盖)。整页图 16:9 + 竖版两张。 - 人物素材:**图生图 + 抠白底**(`image1` 给立绘、`input_fidelity: high`、`flat vector illustration, no outlines`)。 ⚠️ 正面立绘直接贴进空场景像贴纸:改**侧后方视角**(不直视访客),RGB **压白 12~16%** 与压白 38% 的场景对齐雾度。 - ⚠️ **抠白底容差 16**:背景 253、白袜子 237 只差 16,容差 22 以上会把袜子吃穿。手内侧/两腿之间是 **闭合**白区,四边 floodfill 进不去,得按连通域单独掏(面积 ≥24),再 1px 收边。 - ⚠️ `ruleBody` 取令牌前要剥 `/* */`:注释会和后面的令牌粘成一个键,色块预览静默失效。 - ⚠️ **主题会覆盖 base.css 的同名令牌 —— 基座改配色必须同步改主题**。改 `--tb-text-muted` 时 sakura `#a08c94`(2.8:1)、shiroko `#8794a7`(2.76:1) 都还没跟上,"修了但主题页没变"就是这么来的。 现已调到 `#78696e`(4.61) / `#656e7a`(4.63),深色块 `#a18790` / `#7f8ea1`(对压平后的卡片 4.62)。 主色也已修(`#0e6fd0` / `#3b6dac` / `#ba3e66`)+ 新增 `--tb-on-primary`,见 topics/style.md。 量对比度时半透明 `--tb-surface` 要**压平到 --tb-bg** 再算,别当纯白。 - 主题选择页的色块由浅色块的 `--tb-bg` + `--tb-primary` 生成(`swatchOf`),注释里别写令牌名。 - `test01` 是用户 2026-10-21 自建又删掉的验证主题(css + 2 张 webp 已移除,未提交)。 删主题只需删文件:`build()` 读不到 css 会打 warning 并忽略,已选该主题的用户静默回退站点默认。 `static/images/shiroko-cutout.png` 也一并删除(2026-10-21):它从不进 embed,只是 docs 里的图生图参考图, 仓库不存这类大图。 - ⚠️ **白上白素材无法用颜色分开**:白底 + 白主体(如自行车)时,车身与背景是同一个白 (实测都 `#f9f9f9`),floodfill 只吃外圈,轮圈内/车架三角/车筐整块留下 = 看着"没抠干净"。 自检:`不透明像素里近白(>240) 占比`,正常应≈0(修复前 50%)。要么全部转透明(成品变线稿风), 要么重出绿幕/透明背景素材。细节见 `docs/theme-shiroko-assets-spec.md` 的「白上白」。 - ⚠️ 换 `props/*.webp` 时**不要裁画布**:`--tb-deco-size` 是 `auto 259px`,宽度按原图比例算, 裁完锚点 `left calc(50% - 612px)` 会漂;四周透明边留着不影响观感。