styles/ 是全家族元件 BEM 樣式的唯一源(紅線 2):58 個元件目錄 + theme/common/ 令牌層。任何 UI 庫都不得把樣式拷出去手改。
├── index.scss # 全量聚合(令牌 + 全部元件),一行引入
│ │ ├── var.scss # 明色令牌(:root,185 條 CSS 變數)
│ │ ├── var-dark.scss # 暗色覆蓋([data-theme='dark'], .dark,118 條)
│ │ ├── variables.scss # SCSS 變數層(183 個 $lh-*,編譯期常數)
│ │ ├── patterns.scss # 國風花紋系統(6 紋理)
│ │ ├── transition.scss # 跨端過渡類別名單源(3 個 mixin)
│ │ └── … # mixin / function 公共層
│ └── index.scss # 主題聚合入口
├── button/index.scss # 元件樣式(58 個目錄)
每個元件目錄就是一個 index.scss,按 @lh-ui/share/styles/<name> 匯入(vite 目錄解析到 index)。
import '@lh-ui/share/styles/button' // 單個元件
import '@lh-ui/share/styles' // 全量(styles/index.scss)
import '@lh-ui/share/styles/theme' // 僅主題令牌
import '@lh-ui/share/styles/theme/common/var-dark' // 細到具體檔案
各 UI 庫的注入策略不同:plus 在庫入口全量注入,vue2 由使用者按需引(見 注入策略)。
類別名一律 lh- 前綴 + BEM 三層:
&--primary { } // Modifier
&__text--disabled { } // Element + Modifier
&.is-loading { } // 狀態類(is- 前綴,不帶命名空間)
- 命名由 createNamespace 生成,保證全家族一致。
- 狀態類用
is- 前綴(is-loading / is-disabled / is-open),不是 BEM 修飾符。
- 新增類別名需同步更新
docs/src/data/classes.json(由 scripts/gen-docs-data.mjs 掃描 styles/*/index.scss 生成)。
| 層 |
檔案 |
數量 |
特性 |
| CSS 變數(明色) |
var.scss |
185 條 |
:root { --lh-*: ... },執行時可覆蓋 |
| CSS 變數(暗色) |
var-dark.scss |
118 條 |
[data-theme='dark'], .dark { ... } 覆蓋明色 |
| SCSS 變數 |
variables.scss |
183 個 |
$lh-*,編譯期烤死 |
color: var(--lh-color-on-primary, #fff);
background: var(--lh-primary-color, #1677ff);
// ❌ 錯誤:直接引用 SCSS 變數,暗色下不會翻轉
background: #{$lh-primary-color};
var.scss 裡值形如 #{$lh-foo} 的令牌,SCSS 變數在編譯期被替換成具體明色值,暗色下不會自動翻轉。這類令牌必須在 var-dark.scss 裡顯式重新指向暗色語義令牌:
--lh-menu-item-color: var(--lh-text-primary); // ← 顯式重指向
此類缺口曾導致暗色下選單 / 表格 / 時間軸文字沿用明色值而不可見。pnpm verify:styles 第 7 項(暗色可達性)專門把關。相對地,元件裡 var(--lh-foo, var(--lh-bar, #x)) 的鏈式回落是執行時求值,只要鏈上令牌有暗色覆蓋即安全,無需重複宣告。詳見 暗色模式。
全量聚合檔案由 scripts/build-styles.mjs 按元件目錄掃描生成,verify:styles 驗證一致性——不要手改。新增元件目錄會自動被聚合覆蓋。
1px 細邊框宣告必須帶 /* hairline */ 行級標記 —— 這條紅線已廢止(uniapp v3 px 直出,不再轉譯 rpx,標記失去用途;見 docs/bugfix-log.md D-02)。styles/ 內既有的 65 處歷史標記保留為普通註解,新增 1px 邊框無需再標記。結構性邊框(2px / 3px)原本就不標記。
主色与衍生语义
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-primary-color | | #3D649E | $lh-primary | |
--lh-primary-color-hover | | #5078AB | $lh-primary-hover | |
--lh-primary-color-active | | #2B4C7C | $lh-primary-active | |
--lh-primary-color-bg | | color-mix(in srgb, var(--lh-primary-color) 25%, transparent) | $lh-primary-light | |
--lh-primary-color-border | | #2A3A4A | $lh-primary-lighter | |
--lh-color-on-primary | | #fff | $lh-on-primary | |
状态
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-hover-bg-color | | rgba(255, 255, 255, 0.08) | $lh-hover-bg | |
--lh-selected-color | | color-mix(in srgb, var(--lh-primary-color) 40%, #fff) | — | |
功能色
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-success-color | | #6FA36E | $lh-success | |
--lh-success-color-hover | | #82B581 | $lh-success-hover | |
--lh-success-color-active | | #5B8C5A | $lh-success-active | |
--lh-success-color-bg | | #1A2A1A | $lh-success-light | |
--lh-warning-color | | #D4B76F | $lh-warning | |
--lh-warning-color-hover | | #E0C680 | $lh-warning-hover | |
--lh-warning-color-active | | #C4A35A | $lh-warning-active | |
--lh-warning-color-bg | | #2A251A | $lh-warning-light | |
--lh-danger-color | | #C45050 | $lh-danger | |
--lh-danger-color-hover | | #D46060 | $lh-danger-hover | |
--lh-danger-color-active | | #B23A3A | $lh-danger-active | |
--lh-danger-color-bg | | #2A1A1A | $lh-danger-light | |
--lh-info-color | | #8F8F8F | $lh-info | |
--lh-info-color-hover | | #A0A0A0 | $lh-info-hover | |
--lh-info-color-active | | #7A7A7A | $lh-info-active | |
--lh-info-color-bg | | #1A1A1A | $lh-info-light | |
国风装饰色
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-gold-color | | #D4A843 | $lh-gold | |
--lh-gold-color-hover | | #E8C35C | $lh-gold-hover | |
--lh-gold-color-active | | #B8860B | $lh-gold-active | |
--lh-gold-color-bg | | #2A241A | $lh-gold-light | |
--lh-gold-color-border | | #3A2E1A | $lh-gold-lighter | |
--lh-vermilion-color | | #E85D4A | $lh-vermilion | |
--lh-vermilion-color-hover | | #FF7B6B | $lh-vermilion-hover | |
--lh-vermilion-color-active | | #C43A31 | $lh-vermilion-active | |
--lh-vermilion-color-bg | | #2A1A18 | $lh-vermilion-light | |
--lh-jade-color | | #7AAE7A | $lh-jade | |
--lh-jade-color-hover | | #9CC89C | $lh-jade-hover | |
--lh-jade-color-active | | #5B8C5A | $lh-jade-active | |
--lh-jade-color-bg | | #1A2A1A | $lh-jade-light | |
--lh-decoration-color | | rgba(212, 168, 67, 0.08) | $lh-decoration-color | |
文本
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-text-primary | | #E8E0D8 | $lh-text-primary | |
--lh-text-regular | | #C8C0B8 | $lh-text-regular | |
--lh-text-secondary | | #A09890 | $lh-text-secondary | |
--lh-text-placeholder | | #7A7270 | $lh-text-placeholder | |
--lh-text-disabled | | #5A5250 | $lh-text-disabled | |
边框
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-border-color-base | | #3A3530 | $lh-border-color-base | |
--lh-border-color-light | | #302B28 | $lh-border-color-light | |
--lh-border-color-lighter | | #2A2520 | $lh-border-color-lighter | |
--lh-border-color-extra-light | | #242018 | $lh-border-color-extra-light | |
圆角
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-border-radius-base | | 沿用明色 | $lh-border-radius-base | |
--lh-border-radius-small | | 沿用明色 | $lh-border-radius-small | |
--lh-border-radius-round | | 沿用明色 | $lh-border-radius-round | |
--lh-border-radius-circle | | 沿用明色 | $lh-border-radius-circle | |
背景
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-bg-color | | #2A2520 | $lh-bg-color | |
--lh-bg-color-page | | #1E1A16 | $lh-bg-color-page | |
--lh-bg-color-disabled | | #242018 | $lh-bg-color-disabled | |
--lh-bg-color-overlay | | rgba(10, 8, 6, 0.7) | $lh-bg-color-overlay | |
阴影
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-box-shadow-base | | 0 2px 12px 0 rgba(0, 0, 0, 0.5) | $lh-box-shadow-base | |
--lh-box-shadow-light | | 0 2px 4px 0 rgba(0, 0, 0, 0.4) | $lh-box-shadow-light | |
--lh-box-shadow-lighter | | 0 0 4px 0 rgba(0, 0, 0, 0.3) | $lh-box-shadow-lighter | |
字体
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-font-family | | 沿用明色 | $lh-font-family | |
--lh-font-size-extra-large | | 沿用明色 | $lh-font-size-extra-large | |
--lh-font-size-large | | 沿用明色 | $lh-font-size-large | |
--lh-font-size-medium | | 沿用明色 | $lh-font-size-medium | |
--lh-font-size-base | | 沿用明色 | $lh-font-size-base | |
--lh-font-size-small | | 沿用明色 | $lh-font-size-small | |
--lh-font-size-extra-small | | 沿用明色 | $lh-font-size-extra-small | |
--lh-font-weight-primary | | 沿用明色 | $lh-font-weight-primary | |
--lh-font-weight-bold | | 沿用明色 | $lh-font-weight-bold | |
--lh-font-line-height-primary | | 沿用明色 | $lh-font-line-height-primary | |
组件级 · control
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-control-height-mini | | 沿用明色 | $lh-control-height-mini | |
--lh-control-height-small | | 沿用明色 | $lh-control-height-small | |
--lh-control-height-medium | | 沿用明色 | $lh-control-height-medium | |
--lh-control-height-large | | 沿用明色 | $lh-control-height-large | |
--lh-control-height-x-large | | 沿用明色 | $lh-control-height-x-large | |
间距
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-spacing-xs | | 沿用明色 | $lh-spacing-xs | |
--lh-spacing-sm | | 沿用明色 | $lh-spacing-sm | |
--lh-spacing-md | | 沿用明色 | $lh-spacing-md | |
--lh-spacing-base | | 沿用明色 | $lh-spacing-base | |
--lh-spacing-lg | | 沿用明色 | $lh-spacing-lg | |
--lh-spacing-xl | | 沿用明色 | $lh-spacing-xl | |
--lh-spacing-xxl | | 沿用明色 | $lh-spacing-xxl | |
层级
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-z-index-normal | | 沿用明色 | $lh-z-index-normal | |
--lh-z-index-dropdown | | 沿用明色 | $lh-z-index-dropdown | |
--lh-z-index-sticky | | 沿用明色 | $lh-z-index-sticky | |
--lh-z-index-fixed | | 沿用明色 | $lh-z-index-fixed | |
--lh-z-index-modal-backdrop | | 沿用明色 | $lh-z-index-modal-backdrop | |
--lh-z-index-modal | | 沿用明色 | $lh-z-index-modal | |
--lh-z-index-popover | | 沿用明色 | $lh-z-index-popover | |
--lh-z-index-tooltip | | 沿用明色 | $lh-z-index-tooltip | |
过渡
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-transition-duration-fast | | 沿用明色 | $lh-transition-duration-fast | |
--lh-transition-duration-base | | 沿用明色 | $lh-transition-duration-base | |
--lh-transition-duration-slow | | 沿用明色 | $lh-transition-duration-slow | |
--lh-transition-function-ease-in-out | | 沿用明色 | $lh-transition-function-ease-in-out | |
禁用态
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-disabled-bg-color | | #242018 | $lh-disabled-bg-color | |
--lh-disabled-text-color | | #5A5250 | $lh-disabled-text-color | |
--lh-disabled-border-color | | #302B28 | $lh-disabled-border-color | |
--lh-disabled-opacity | | 0.5 | $lh-disabled-opacity | |
组件级 · popover
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-popover-bg-color | | #2A2520 | $lh-popover-bg-color | |
--lh-popover-border-color | | #3A3530 | $lh-popover-border-color | |
--lh-popover-border-radius | | 沿用明色 | $lh-popover-border-radius | |
--lh-popover-padding | | 沿用明色 | $lh-popover-padding | |
--lh-popover-title-color | | #E8E0D8 | $lh-popover-title-color | |
--lh-popover-content-color | | #C8C0B8 | $lh-popover-content-color | |
--lh-popover-arrow-size | | 沿用明色 | $lh-popover-arrow-size | |
组件级 · popconfirm
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-popconfirm-padding | | 沿用明色 | $lh-popconfirm-padding | |
--lh-popconfirm-icon-size | | 沿用明色 | $lh-popconfirm-icon-size | |
组件级 · drawer
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-drawer-bg-color | | #2A2520 | $lh-drawer-bg-color | |
--lh-drawer-border-color | | #3A3530 | $lh-drawer-border-color | |
--lh-drawer-header-padding | | 沿用明色 | $lh-drawer-header-padding | |
--lh-drawer-body-padding | | 沿用明色 | $lh-drawer-body-padding | |
--lh-drawer-footer-padding | | 沿用明色 | $lh-drawer-footer-padding | |
--lh-drawer-title-color | | #E8E0D8 | $lh-drawer-title-color | |
--lh-drawer-close-size | | 沿用明色 | $lh-drawer-close-size | |
组件级 · dropdown
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-dropdown-bg-color | | #2A2520 | $lh-dropdown-bg-color | |
--lh-dropdown-border-color | | #3A3530 | $lh-dropdown-border-color | |
--lh-dropdown-border-radius | | 沿用明色 | $lh-dropdown-border-radius | |
--lh-dropdown-padding | | 沿用明色 | $lh-dropdown-padding | |
--lh-dropdown-item-height | | 沿用明色 | $lh-dropdown-item-height | |
--lh-dropdown-item-padding | | 沿用明色 | $lh-dropdown-item-padding | |
--lh-dropdown-item-color | | #C8C0B8 | $lh-dropdown-item-color | |
--lh-dropdown-item-hover-bg-color | | var(--lh-hover-bg-color) | $lh-dropdown-item-hover-bg-color | |
--lh-dropdown-divider-color | | #302B28 | $lh-dropdown-divider-color | |
组件级 · message
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-message-bg | | #2A2520 | $lh-message-bg-color | |
--lh-message-border | | #3A3530 | $lh-message-border-color | |
--lh-message-color | | #C8C0B8 | $lh-message-content-color | |
--lh-message-shadow | | 沿用明色 | $lh-message-shadow | |
组件级 · notification
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-notification-bg | | #2A2520 | $lh-notification-bg-color | |
--lh-notification-border | | #3A3530 | $lh-notification-border-color | |
--lh-notification-title-color | | #E8E0D8 | $lh-notification-title-color | |
--lh-notification-content-color | | #C8C0B8 | $lh-notification-content-color | |
--lh-notification-width | | 沿用明色 | $lh-notification-width | |
--lh-notification-gap | | 沿用明色 | $lh-notification-gap | |
--lh-notification-shadow | | 沿用明色 | $lh-notification-shadow | |
组件级 · loading
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-loading-bg | | rgba(10, 8, 6, 62%) | $lh-loading-bg-color | |
--lh-loading-text-color | | #C8C0B8 | $lh-loading-text-color | |
组件级 · timeline
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-timeline-line | | #302B28 | $lh-timeline-line | |
--lh-timeline-dot | | var(--lh-info-color) | $lh-timeline-dot | |
--lh-timeline-timestamp | | var(--lh-text-secondary) | $lh-timeline-timestamp | |
组件级 · collapse
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-collapse-border | | #302B28 | $lh-collapse-border | |
组件级 · rate
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-rate-active | | var(--lh-warning-color) | $lh-rate-active | |
组件级 · segmented
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-segmented-bg | | #242018 | $lh-segmented-bg | |
组件级 · calendar
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-calendar-border | | var(--lh-border-color-lighter) | $lh-calendar-border | |
组件级 · affix
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-affix-z-index | | 沿用明色 | $lh-affix-z-index | |
组件级 · backtop
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-backtop-z-index | | 沿用明色 | $lh-backtop-z-index | |
组件级 · menu
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-menu-bg | | #242018 | $lh-menu-bg | |
--lh-menu-padding | | 沿用明色 | $lh-menu-padding | |
--lh-menu-border | | #302B28 | $lh-menu-border | |
--lh-menu-height | | 沿用明色 | $lh-menu-height | |
--lh-menu-collapse-width | | 沿用明色 | $lh-menu-collapse-width | |
--lh-menu-item-height | | 沿用明色 | $lh-menu-item-height | |
--lh-menu-item-padding | | 沿用明色 | $lh-menu-item-padding | |
--lh-menu-item-color | | var(--lh-text-primary) | $lh-menu-item-color | |
--lh-menu-item-hover-bg | | #302B28 | $lh-menu-item-hover-bg | |
--lh-menu-item-active-color | | var(--lh-selected-color) | $lh-menu-item-active-color | |
--lh-menu-item-active-bg | | var(--lh-primary-color-bg) | $lh-menu-item-active-bg | |
--lh-menu-arrow-color | | var(--lh-text-secondary) | $lh-menu-arrow-color | |
--lh-menu-z-index | | 沿用明色 | $lh-menu-z-index | |
组件级 · table
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-table-bg | | #242018 | $lh-table-bg | |
--lh-table-color | | var(--lh-text-regular) | $lh-table-color | |
--lh-table-header-bg | | #2A2420 | $lh-table-header-bg | |
--lh-table-header-color | | var(--lh-text-primary) | $lh-table-header-color | |
--lh-table-border | | #302B28 | $lh-table-border | |
--lh-table-row-hover-bg | | #2A2420 | $lh-table-row-hover-bg | |
--lh-table-stripe-bg | | color-mix(in srgb, var(--lh-bg-color-page) 60%, transparent) | $lh-table-stripe-bg | |
--lh-table-cell-padding | | 沿用明色 | $lh-table-cell-padding | |
组件级 · layout
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-layout-header-height | | 沿用明色 | $lh-layout-header-height | |
--lh-layout-header-bg | | #242018 | $lh-layout-header-bg | |
--lh-layout-aside-width | | 沿用明色 | $lh-layout-aside-width | |
--lh-layout-aside-bg | | #242018 | $lh-layout-aside-bg | |
--lh-layout-main-bg | | #1C1815 | $lh-layout-main-bg | |
--lh-layout-border | | #302B28 | $lh-layout-border | |
组件级 · row
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-row-gutter | | 沿用明色 | $lh-row-gutter | |
组件级 · tree
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-tree-color | | #D8D0C8 | $lh-tree-color | |
--lh-tree-padding | | 沿用明色 | $lh-tree-padding | |
--lh-tree-node-height | | 沿用明色 | $lh-tree-node-height | |
--lh-tree-node-hover-bg | | #2A2420 | $lh-tree-node-hover-bg | |
--lh-tree-node-selected-color | | var(--lh-selected-color) | $lh-tree-node-selected-color | |
--lh-tree-node-selected-bg | | var(--lh-primary-color-bg) | $lh-tree-node-selected-bg | |
--lh-tree-arrow-color | | var(--lh-text-secondary) | $lh-tree-arrow-color | |
组件级 · transfer
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-transfer-panel-width | | 沿用明色 | $lh-transfer-panel-width | |
--lh-transfer-panel-height | | 沿用明色 | $lh-transfer-panel-height | |
--lh-transfer-bg | | #242018 | $lh-transfer-bg | |
--lh-transfer-border | | #302B28 | $lh-transfer-border | |
组件级 · upload
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-upload-bg | | #242018 | $lh-upload-bg | |
--lh-upload-border | | var(--lh-border-color-base) | $lh-upload-border | |
--lh-upload-trigger-padding | | 沿用明色 | $lh-upload-trigger-padding | |
组件级 · anchor
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-anchor-color | | var(--lh-text-regular) | $lh-anchor-color | |
组件级 · image
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-image-viewer-mask | | rgba(0, 0, 0, 80%) | — | |
无障碍焦点环
| 令牌 | 明色 | 暗色 | SCSS 源 | 备注 |
|---|
--lh-focus-color | | #7FA6D9 | $lh-primary | |
--lh-focus-ring-width | | 沿用明色 | — | |
--lh-focus-ring-offset | | 沿用明色 | — | |
(令牌資料由 scripts/gen-docs-data.mjs 解析 var.scss / var-dark.scss / variables.scss 生成,帶數量斷言。)
- 改樣式只在本倉庫:任何 UI 庫不得持有元件 scss 副本。跨端過渡類別名差異用 transition mixin 收編。
- 顏色一律
var(--lh-*, fallback),不新增硬編碼色值(verify:styles 的 var fallback 項把關)。
- 新增元件必須有
styles/<name>/index.scss,否則該元件在某一端無樣式產物(構建腳本靜默跳過,不會報錯)。
- 暗色完備性是硬要求:所有元件預設支援明暗兩色,暗色缺口由 verify:styles 第 7 項攔截。