跳转到内容

布局与主题

外观相关的一切:布局结构、Tailwind v4 的用法与陷阱、主题系统、偏好同步。

布局

packages/layouts/ 提供整套外壳:侧边栏、顶栏、标签页(tabbar)、内容区、页脚。

滚动模型

滚动源不是 window

布局根是定高的(h-full),滚动发生在内容容器内部。这意味着:

  • 监听 window 的 scroll 事件拿不到滚动;
  • 需要吸顶/吸底的整屏页直接用 h-fullXPageShell 即可;
  • 不要写 per-page 的 JS 定高 hack

回到顶部、路由切换重置滚动都已由布局适配器统一处理。

样式:Tailwind CSS 4(CSS-first)

@tailwindcss/vite + CSS-first @theme(入口 src/styles/index.css),没有 JS config 文件

三条关键约定:

约定说明
只引入 theme + utilities,不引入 preflight基础重置由 Naive UI 与 design/global.css 的最小重置负责,避免与 Naive UI 打架
颜色令牌用运行时 HSL CSS 变量--color-primary: hsl(var(--primary)) 等,保证明暗与主题色能动态切换
暗色走 class 策略@custom-variant dark (&:where(.dark, .dark *))

嵌套 .dark 的坑

深色侧栏里 bg-* / text-* 不变暗

@theme 里声明的 --color-* 只在 :root 解析。深色侧栏、深色子栏、深色顶栏这类嵌套 .dark 的容器里,Tailwind 的颜色工具类拿不到暗色值,表现是「局部深色区域里的元素还是亮色」。

修法:在 variables.css:root, .dark 块里重新声明全部 --color-*,让嵌套作用域也能解析到。

主题系统

useTheme()~/hooks/useTheme.ts)管理外观:

维度可调
明暗亮 / 暗 / 跟随系统
主题色任意品牌色
形状圆角
排版字号

Material You 动态取色

从单个品牌色派生整套和谐色阶——辅色、容器色、前景色、聚焦环、带品牌色相的中性色,明暗自适应,以内联 CSS 变量写到根元素。

所以换主题色不需要改任何 CSS:改一个色值,整套配色跟着重算。

主色、明暗、圆角、字号变化都会同步到 CSS 变量,非 Naive 的自定义元素也能直接用这些变量。

切换动画

startViewTransition 从点击处圆形扩散——明暗切换时的视觉过渡。

偏好同步

UI 偏好走 UserSettingAppService,按场景 + key 存取:

text
localStorage(事实源)

后端 SysUserSetting(用户 × 场景 × 设置键)
   ↕ SignalR UserSettingChanged
其它设备已打开的页面即时应用

三条策略:

  1. localStorage 是事实源——后端加载成功则覆盖本地,保存失败静默忽略(尽力而为,不阻断交互)。
  2. 服务端不解释 value,只作跨端状态载体。
  3. 其它设备保存后经 SignalR 广播实时应用。

Schema 页的列设置、搜索设置、个人视图按 pageCode 走同一套机制,见 Schema 驱动页面

pageCode 要稳定

偏好按 pageCode 存储,改了等于用户的所有个性化配置丢失。页面上线后不要再动它。

排查

现象原因
深色区域里的元素还是亮色嵌套 .dark 令牌问题,见上面的 danger 块
改了主题色但某些地方没变那些地方写死了颜色值,没用 CSS 变量
页面滚不动 / 吸顶失效用了 window 滚动的假设;改用 h-fullXPageShell
样式被 Naive UI 覆盖preflight 是故意关闭的,别去打开——会破坏 Naive UI
偏好换台设备就没了后端保存失败被静默忽略了,查接口是否可用

相关页面

Released under The MIT License