# 主题的页面作用域(data-page-scope) 一套主题过去只能有一种装饰:人物永远站在左下角,不管当前是箱主页、单题页还是题目列表。 单题页正文长、题目列表信息密,同一套装饰在三种页面上要同时成立很难。 现在服务端会按请求路径给 `` 打一个 `data-page-scope`,主题可以对每个页面分别配 整页背景与装饰层。 ## 取值 | 值 | 路径 | 说明 | | --- | --- | --- | | (无属性) | — | 全局默认 | | `box` | `/_/{domain}`、`/_/{domain}/tag/*` | 箱主页(问题列表) | | `question` | `/_/{domain}/{qid}` | 单个问题 | | `admin` | `/user/questions`、`/user/votes/*` | 题目 / 私聊管理列表 | | `profile` | `/user`、`/user/profile` 等 | 设置页 | | `vote` | `/vote/{token}` | 投票页(跟随发布者的主题) | | `home` / `explore` | `/`、`/explore` | Go 侧会返回,但**这两页不加载主题 css** | 来源:`internal/context.pageScope()`,测试在 `internal/context/context_test.go` 的 `TestPageScope`。 ## 选择器与特异性 ```css /* 全局 */ html[data-theme-style="SLUG"] { … } /* 某一页覆盖 */ html[data-theme-style="SLUG"][data-page-scope="question"] { … } ``` 特异性 0,2,1 与深色块 `html[data-theme="dark"][data-theme-style="SLUG"]` 相同, 而覆盖块写在文件后面,**会盖掉深色块**。所以深色必须再写一条三重选择器: ```css html[data-theme="dark"][data-theme-style="SLUG"][data-page-scope="question"] { … } ``` 不写的话,深色模式下会拿到浅色的覆盖块 —— 典型表现是「深色页面里突然出现一块白天场景」。 ## 覆盖块写什么 通常只覆盖这三组: ```css html[data-theme-style="SLUG"][data-page-scope="question"] { --tb-page-image: none; /* 不放整页场景 */ --tb-page-pattern: none; --tb-deco: …; /* 10 个值 */ --tb-deco-size: …; /* 10 个值 */ --tb-deco-position: …; /* 10 个值 */ } ``` 配色(`--tb-bg` / `--tb-surface` / `--tb-text` / `--tb-primary`)一般不要按页面改: 同一个主题在不同页面换配色,用户会觉得走错站了。 ## 10 个槽位 `--tb-deco` / `--tb-deco-size` / `--tb-deco-position` 三组必须**等长且写满 10 个**。 少一个不会报错,CSS 会按列表长度循环取值,于是图层与 size/position 整体错位: - 整页重复同一张插画(第一次踩坑就是这个) - 人物跑到页面左上角(`background-position` 整条声明非法时回落初始值) `internal/theme/slots_test.go` 的 `TestDecoSlotCount` 会逐个文件、逐处声明检查, 包括 base.css 与所有主题 css(含作用域覆盖块)。写主题时不用记,跑测试就行。 `background-position` 一律写成两值 `calc()`: ```css --tb-deco-position: calc(0% + 40px) calc(100% - 36px), calc(50% + 0px) calc(50% + 0px), …; ``` - 百分比是相对 **(容器 − 图片)** 的剩余空间,不是相对容器 - `0%` 左/上、`50%` 居中、`100%` 右/下 - **不要**混用 `left` / `bottom` 关键字:「水平居中 + 垂直贴底」会变成三值语法, 一旦不合规范整条声明作废,图层静默掉到左上角 ## 可视化编辑 手写这些值不现实,用 `dev/theme-builder/`(见同目录 README):以真实页面为画布, 按页面切换、拖拽定位、导出 zip。它生成的 CSS 直接过 `TestThemeCSSComplete` 与 `TestDecoSlotCount`。