Skip to content

主题定制

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-softrgba(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#1c2330hover 底色
--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-h48px顶栏高度
--fmb-toolbar-h48px工具条高度(当前未被组件消费,预留)
--fmb-rail-w48px左侧图标 rail 宽度
--fmb-rpanel-w312px右侧面板(<fmb-inspector>)宽度
--fmb-lpanel-w256px左侧面板(结构树)宽度

圆角

Token默认值用途
--fmb-radius-sm4px小圆角
--fmb-radius6px常规圆角(按钮、输入框)
--fmb-radius-lg8px大圆角(弹层、菜单)
--fmb-radius-xl12px超大圆角(浮动工具条)

阴影

Token默认值暗色值用途
--fmb-shadow-sm0 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-md0 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-lg0 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-pop0 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-fs14px基准字号(密度驱动)

暗色模式

暗色不是独立样式表,而是 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-h48px42px56px
--fmb-toolbar-h48px42px56px
--fmb-rail-w48px44px52px
--fmb-base-fs14px13px15px

覆写示例:换主色

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 等),完整布局示例见完整集成示例