Appearance
主题定制
viewer-ui 组件的视觉由一套 CSS 自定义属性(design tokens)驱动,集中定义在包内的 tokens.css。组件样式封装在 Shadow DOM 里,token 是唯一受支持的定制面——改 token 即换肤,不需要(也无法)从外部直接选中组件内部节点。
引入 tokens.css
包的 exports 提供了 ./tokens.css 子路径,在 JS 入口或 CSS 里引一次即可:
ts
import "@modelcubes/viewer-ui/tokens.css";css
/* 或在你的全局 CSS 里(@fmb/viewer 阅读器 app 即此用法) */
@import "@modelcubes/viewer-ui/tokens.css";组件内部消费 token 时都带回退值(var(--fmb-surface, #fff)),所以不引 tokens.css 组件也能以内置浅色渲染;但要统一调色、切暗色或调密度,就需要引入它——暗色与密度变体都定义在这份文件里。
Token 总表
以下为 tokens.css 全量内容,按文件实际分组。「暗色值」列是 [data-theme='dark'] 下的覆写;留空表示暗色沿用默认值。
颜色 — 主色
| Token | 默认值 | 暗色值 | 用途 |
|---|---|---|---|
--fmb-accent | #3B82F6 | 主色:选中态、激活按钮、滑杆等 | |
--fmb-accent-hover | #2563eb | 主色 hover 态 | |
--fmb-accent-soft | rgba(59, 130, 246, 0.1) | rgba(59, 130, 246, 0.16) | 主色弱化底色(选中行/激活按钮背景) |
--fmb-accent-fg | #1d4ed8 | #93c5fd | 主色前景文字(浅底上的深蓝/暗底上的亮蓝) |
颜色 — 背景 / 表面 / 边框
| Token | 默认值 | 暗色值 | 用途 |
|---|---|---|---|
--fmb-bg | #f4f6f9 | #0a0e14 | 页面/视口背景 |
--fmb-surface | #ffffff | #11161d | 面板、工具条、弹层表面 |
--fmb-surface-2 | #f8fafc | #161c25 | 次级表面(输入框底、徽标底) |
--fmb-surface-3 | #eef1f5 | #1b222c | 三级表面(滑杆轨道等) |
--fmb-surface-hover | #f1f4f8 | #1c2330 | hover 底色 |
--fmb-border | #e2e6ed | #1e2530 | 常规边框/分隔线 |
--fmb-border-strong | #d4d9e1 | #2a3340 | 强调边框 |
颜色 — 前景与语义色
| Token | 默认值 | 暗色值 | 用途 |
|---|---|---|---|
--fmb-fg-1 | #0b1220 | #e6e8eb | 一级前景(正文/标题) |
--fmb-fg-2 | #475569 | #94a3b8 | 二级前景(次要文字、图标) |
--fmb-fg-3 | #94a3b8 | #64748b | 三级前景(占位符、辅助信息) |
--fmb-fg-4 | #cbd5e1 | #475569 | 四级前景(禁用态) |
--fmb-danger | #ef4444 | 危险动作(工具条状态条 ✕ hover、剖切面 Remove) |
布局尺寸(密度驱动)
| Token | 默认值 | 用途 |
|---|---|---|
--fmb-header-h | 48px | 顶栏高度 |
--fmb-toolbar-h | 48px | 工具条高度(当前未被组件消费,预留) |
--fmb-rail-w | 48px | 左侧图标 rail 宽度 |
--fmb-rpanel-w | 312px | 右侧面板(<fmb-inspector>)宽度 |
--fmb-lpanel-w | 256px | 左侧面板(结构树)宽度 |
圆角
| Token | 默认值 | 用途 |
|---|---|---|
--fmb-radius-sm | 4px | 小圆角 |
--fmb-radius | 6px | 常规圆角(按钮、输入框) |
--fmb-radius-lg | 8px | 大圆角(弹层、菜单) |
--fmb-radius-xl | 12px | 超大圆角(浮动工具条) |
阴影
| Token | 默认值 | 暗色值 | 用途 |
|---|---|---|---|
--fmb-shadow-sm | 0 1px 2px rgba(15, 23, 42, 0.04), 0 1px 1px rgba(15, 23, 42, 0.04) | 0 1px 2px rgba(0, 0, 0, 0.4) | 小阴影 |
--fmb-shadow-md | 0 4px 12px rgba(15, 23, 42, 0.06), 0 1px 3px rgba(15, 23, 42, 0.05) | 0 4px 12px rgba(0, 0, 0, 0.4), 0 1px 3px rgba(0, 0, 0, 0.4) | 中阴影 |
--fmb-shadow-lg | 0 12px 40px rgba(15, 23, 42, 0.12), 0 2px 8px rgba(15, 23, 42, 0.08) | 0 12px 40px rgba(0, 0, 0, 0.5), 0 2px 8px rgba(0, 0, 0, 0.4) | 大阴影(弹层、菜单) |
--fmb-shadow-pop | 0 8px 24px rgba(15, 23, 42, 0.14), 0 1px 2px rgba(15, 23, 42, 0.08) | 0 8px 24px rgba(0, 0, 0, 0.5), 0 1px 2px rgba(0, 0, 0, 0.4) | 浮起阴影(工具条) |
字体
| Token | 默认值 | 用途 |
|---|---|---|
--fmb-font | "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", system-ui, sans-serif | 正文字体栈 |
--fmb-mono | "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace | 等宽字体栈(数值、快捷键) |
--fmb-base-fs | 14px | 基准字号(密度驱动) |
暗色模式
暗色不是独立样式表,而是 tokens.css 里 [data-theme='dark'] 选择器下的一组 token 覆写(见上表「暗色值」列)。在 <html> 上切换 data-theme 即全局换肤:
ts
document.documentElement.setAttribute("data-theme", "dark"); // 暗色
document.documentElement.setAttribute("data-theme", "light"); // 回浅色(非 dark 即浅色)注意 3D 画布背景不归 CSS 管:canvas 由引擎绘制,需要同步调 viewer.background 的 API。最简做法是把两者收进一个函数,setColor 对齐 --fmb-bg 的两个主题值:
ts
import type { Viewer, Color } from "@modelcubes/viewer-core";
type ThemeName = "light" | "dark";
// 对齐 tokens.css 的 --fmb-bg:light #f4f6f9 / dark #0a0e14
const BG: Record<ThemeName, Color> = {
light: { r: 0xf4 / 255, g: 0xf6 / 255, b: 0xf9 / 255 },
dark: { r: 0x0a / 255, g: 0x0e / 255, b: 0x14 / 255 },
};
function applyTheme(theme: ThemeName, viewer?: Viewer): void {
document.documentElement.setAttribute("data-theme", theme);
viewer?.background.setColor(BG[theme]);
}@fmb/viewer 阅读器 app 在此之上更进一步:用 viewer.background.setGradient(top, bottom) 按主题画冷中性垂直渐变(顶浅底深),见完整集成示例结尾的差异清单。
密度
tokens.css 还内置两档密度变体,机制与主题相同——在 <html>(或任意祖先)上设 data-density:
| Token | 默认 | data-density="compact" | data-density="comfy" |
|---|---|---|---|
--fmb-header-h | 48px | 42px | 56px |
--fmb-toolbar-h | 48px | 42px | 56px |
--fmb-rail-w | 48px | 44px | 52px |
--fmb-base-fs | 14px | 13px | 15px |
覆写示例:换主色
token 是普通 CSS 自定义属性,在 tokens.css 之后声明同名变量即覆写。把主色从蓝换成玫红,连同三个派生值一起改:
css
:root {
--fmb-accent: #e11d48;
--fmb-accent-hover: #be123c;
--fmb-accent-soft: rgba(225, 29, 72, 0.1);
--fmb-accent-fg: #9f1239;
}
[data-theme="dark"] {
--fmb-accent-soft: rgba(225, 29, 72, 0.16);
--fmb-accent-fg: #fda4af;
}作用域不限于 :root——把覆写声明在某个容器选择器下,即可只给页面里的一处 viewer 换肤。
Shadow DOM 与定制边界
- 除
<fmb-viewer-context>(light DOM,无样式)外,组件样式都封装在 Shadow DOM 内,外部 CSS 选择器(如.fmb-tree-row)穿透不进去。 - 组件未暴露
::part(),CSS 自定义属性是唯一受支持的定制面;token 表之外的内部类名/结构不是公开接口,可能随版本变化。 - 组件宿主元素本身(
fmb-model-tree等标签)可以正常从外部设布局类样式(宽度、定位、hidden等),完整布局示例见完整集成示例。