主题与暗色模式
所有视觉效果都来自 @thl-ui/tokens 生成的 CSS 自定义属性。组件从不硬编码颜色,因此皮肤、暗色模式以及你自己的品牌样式都只是 token 覆盖而已。
皮肤
内置 12 套皮肤:6 种品牌色 × 浅色 / 深色侧边栏。
| 皮肤 | 主题色 | 顶栏渐变 |
|---|---|---|
default | #0277b9 | #0078bc → #00beda |
green | #2ecc71 | #25bf67 → #3fdd82 |
yellow | #ffb136 | #f2a225 → #ffbb51 |
red | #d6411d | #d93c17 → #ff704f |
purple | #4a23ad | #4a23ad → #693fd5 |
black | #282f32 | #282f32 → #4b555b |
追加 -dark(例如 green-dark)即可使用深色 #4F5467 侧边栏。通过配置中的 theme 或运行时的 set({ theme }) 设置。可以试试本站顶栏中的皮肤选择器。
无障碍配色对
像 #2ecc71 这样的亮色填充无法在满足 WCAG AA 的前提下承载白色文字(2.1:1)。thl-ui 保留这些色相用于填充,并额外提供配套 token:
| Token | 用途 | 示例 |
|---|---|---|
--thl-on-{color} | 绘制在 --thl-color-{color} 填充之上的文字/图标 | primary 上用白色,success / info / warning 上用深色 #1d2326 |
--thl-color-{color}-text | 在表面上作为文字使用的颜色 | success 文字用 #18713d,danger 文字用 #b5361a |
--thl-on-theme、--thl-theme-text | 当前皮肤的同一组配色对 | green 和 yellow 皮肤在激活的标签页上使用深色文字 |
所有配色对在浅色和暗色模式下的对比度均 ≥ 4.5:1,并由单元测试保证(packages/core/src/core.test.ts → token contrast)。Primary(#0277b9)和 danger(#d6411d)足够深,可以使用白色文字。
暗色模式
colorMode: 'dark' 会切换表面、文字和边框 token;'auto' 跟随操作系统(prefers-color-scheme)并实时更新。本站将 VitePress 的外观开关同步到了 colorMode。
Token
最常用的 token(--thl-*):
| Token | 浅色 | 用途 |
|---|---|---|
--thl-theme | 皮肤 | 强调色:激活菜单、焦点、链接悬停、primary 高亮 |
--thl-topbar-1, --thl-topbar-2 | 皮肤 | 顶栏渐变 |
--thl-color-{primary,success,info,warning,danger,inverse,purple,…} | 调色板 | 语义色 |
--thl-body-bg | #f4f8f9 | 页面背景 |
--thl-surface, --thl-surface-muted | #fff, #f7fafc | 卡片、输入框、表格斑马纹 |
--thl-border-color | #e5ebec | 边框 |
--thl-text, --thl-text-strong, --thl-heading, --thl-link | 文字颜色 | |
--thl-sidebar-bg, --thl-sidebar-text, --thl-sidebar-active | 侧边菜单 | |
--thl-font-family, --thl-font-size, --thl-line-height | Open Sans, 14px, 1.6 | |
--thl-radius-sm, --thl-radius, --thl-radius-lg | 2 / 4 / 6px | radius: 'sharp' → 0 |
--thl-topbar-height, --thl-sidebar-width, --thl-sidebar-mini-width | 60 / 265 / 60px | 布局 |
--thl-z-base | 1000 | 来自 zIndex 配置 |
完整列表:node_modules/@thl-ui/styles/dist/tokens.css。
自定义品牌
在你自己的 CSS 中覆盖 token——全局或按皮肤均可:
:root {
--thl-font-family: 'Inter', system-ui, sans-serif;
--thl-color-primary: #6d28d9;
}
/* 新皮肤:设置 config.theme = 'brand' */
[data-thl-theme='brand'] {
--thl-theme: #6d28d9;
--thl-topbar-1: #5b21b6;
--thl-topbar-2: #8b5cf6;
}
/* 仅调整暗色模式 */
[data-thl-color-mode='dark'] {
--thl-body-bg: #0b0d12;
}theme 的类型是 ThlSkin;对于自定义皮肤,可以进行类型断言或放宽类型:set({ theme: 'brand' as never })。
局部主题
Token 只是普通的 CSS 变量,因此任意子树都可以使用不同的外观:
<section data-thl-theme="red" style="--thl-radius: 12px">
<!-- 此处的组件使用 red 皮肤和更大的圆角 -->
</section>类名前缀
所有类名都遵循 BEM 规范并带有可配置的前缀:.thl-btn、.thl-btn--primary、.thl-btn__icon。如需使用不同的前缀,请在配置中设置 prefix,并且使用 $p 编译 SCSS 源码:
@use '@thl-ui/styles/scss/index' with ($p: 'acme');布局
layout 可在三种 AppLayout 外壳之间切换:
| 值 | 外壳 |
|---|---|
vertical | 完整侧边栏(265px) |
mini | 图标侧边栏(60px),子菜单以浮出方式展开 |
horizontal | 顶部菜单栏 |
宽度低于 1170px 时侧边栏自动变为 mini,低于 768px 时变为抽屉式(off-canvas)菜单(可通过 components.Sidebar.breakpoint 配置)。