콘텐츠로 이동

styles —— 스타일 소스

styles/는 패밀리 전체의 컴포넌트 BEM 스타일 유일 소스입니다(레드라인 2): 58개 컴포넌트 디렉터리 + theme/common/ 토큰 계층. 어떤 UI 라이브러리도 스타일을 밖으로 복사해 직접 수정해서는 안 됩니다.

styles/
├── index.scss # 전체 집계(토큰 + 모든 컴포넌트), 한 줄로 import
├── theme/
│ ├── common/
│ │ ├── 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개 디렉터리)
├── dialog/index.scss
└── …

**각 컴포넌트 디렉터리는 하나의 index.scss**이며, @lh-ui/share/styles/<name>으로 import합니다(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의 3계층:

.lh-button { // Block
&__text { } // Element
&--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-*, 컴파일 타임에 구워짐

컴포넌트는 CSS 변수만 소비할 수 있습니다

섹션 제목: “컴포넌트는 CSS 변수만 소비할 수 있습니다”
// ✅ 올바름: var()의 연쇄 폴백, 런타임에 평가
.lh-button--primary {
color: var(--lh-color-on-primary, #fff);
background: var(--lh-primary-color, #1677ff);
}
// ❌ 틀림: SCSS 변수를 직접 참조, 어두운색에서 전환되지 않음
.lh-button--primary {
background: #{$lh-primary-color};
}

var.scss에서 값이 #{$lh-foo} 형태인 토큰은, SCSS 변수가 컴파일 타임에 구체적인 밝은색 값으로 치환되며, 어두운색에서 자동으로 전환되지 않습니다. 이런 토큰은 var-dark.scss에서 명시적으로 어두운색 의미 토큰을 다시 가리켜야 합니다:

var-dark.scss
[data-theme='dark'],
.dark {
--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번째 항목이 차단합니다.

Copyright © 2024-2026 FengMo WenXue