一、基础颜色定义(源头)
位置:packages/theme-chalk/src/common/var.scss
scss知识点:$ 表示变量
- 定义所有颜色的基础值
js
// types
$types: primary, success, warning, danger, error, info;
// Color
$colors: () !default;
$colors: map.deep-merge(
(
'white': #ffffff,
'black': #000000,
'primary': (
'base': #409eff,
),
'success': (
'base': #67c23a,
),
'warning': (
'base': #e6a23c,
),
'danger': (
'base': #f56c6c,
),
'error': (
'base': #f56c6c,
),
'info': (
'base': #909399,
),
),
$colors
);
二、自动生成颜色变体(light/dark)
位置:packages/theme-chalk/src/common/var.scss
定义一个mixin: set-color-mix-level:
将基础颜色与白色或黑色混合
生成指定级别的浅色或深色变体
将生成的颜色添加到$colors map中
js
// mix colors with white/black to generate light/dark level
@mixin set-color-mix-level(
$type,
$number,
$mode: 'light',
$mix-color: $color-white
) {
$colors: map.deep-merge(
(
$type: (
/**
* roundColor:将颜色的 RGB 通道值四舍五入为整数,并返回 rgba() 格式的颜色。
* color.mix:混合颜色 第一个参数和第二个参数按照第三个参数的百分比混合颜色
* map.get($colors, $type, 'base'):获取颜色
* math.percentage(math.div($number, 10)):将数字转换为百分比
*/
'#{$mode}-#{$number}': roundColor(
color.mix(
$mix-color,
map.get($colors, $type, 'base'),
math.percentage(math.div($number, 10))
)
),
),
),
$colors
) !global;
}
使用
js
// $colors.primary.light-i
// --el-color-primary-light-i
// 10% 53a8ff
// 20% 66b1ff
// 30% 79bbff
// 40% 8cc5ff
// 50% a0cfff
// 60% b3d8ff
// 70% c6e2ff
// 80% d9ecff
// 90% ecf5ff
// 外层循环:遍历颜色类型
@each $type in $types {
// 内层循环:生成 1-9 的变体
@for $i from 1 through 9 {
// 调用 mixin 生成不同亮度的颜色
@include set-color-mix-level($type, $i, 'light', $color-white);
}
}
// 第 1 轮:$type = primary
@include set-color-mix-level(primary, 1, 'light', $color-white); // 生成 primary-light-1
@include set-color-mix-level(primary, 2, 'light', $color-white); // 生成 primary-light-2
@include set-color-mix-level(primary, 3, 'light', $color-white); // 生成 primary-light-3
// ... 继续到 9
// 第 2 轮:$type = success
@include set-color-mix-level(success, 1, 'light', $color-white); // 生成 success-light-1
@include set-color-mix-level(success, 2, 'light', $color-white); // 生成 success-light-2
// ... 继续到 9
// 依此类推,直到遍历完所有 6 种类型
三、生成 CSS 变量(全局)
位置:packages/theme-chalk/src/var.scss
js
// join var name
// joinVarName(('button', 'text-color')) => '--el-button-text-color'
// 将$list遍历中间用-拼接每一个$item
@function joinVarName($list) {
$name: '--' + config.$namespace;
@each $item in $list {
@if $item != '' {
$name: $name + '-' + $item;
}
}
@return $name;
}
===============================================================
// set css var value, because we need translate value to string
// for example:
// @include set-css-var-value(('color', 'primary'), red);
// --el-color-primary: red;
// 返回 变量名:颜色值 的形式
@mixin set-css-var-value($name, $value) {
#{joinVarName($name)}: #{$value};
}
================================================================
@mixin set-css-color-type($colors, $type) {
// 生成基础颜色变量
@include set-css-var-value(('color', $type), map.get($colors, $type, 'base'));
// 结果:--el-color-primary: #409eff;
// 生成浅色变量(3, 5, 7, 8, 9)
@each $i in (3, 5, 7, 8, 9) {
@include set-css-var-value(
('color', $type, 'light', $i),
map.get($colors, $type, 'light-#{$i}')
);
}
// 结果:
// --el-color-primary-light-3: #79bbff;
// --el-color-primary-light-5: #a0cfff;
// --el-color-primary-light-7: #c6e2ff;
// --el-color-primary-light-8: #d9ecff;
// --el-color-primary-light-9: #ecf5ff;
// 生成深色变量
@include set-css-var-value(
('color', $type, 'dark-2'),
map.get($colors, $type, 'dark-2')
);
// 结果:--el-color-primary-dark-2: ...;
}
=================================================================
:root {
color-scheme: light;
// --el-color-#{$type}
// --el-color-#{$type}-light-{$i}
@each $type in (primary, success, warning, danger, error, info) {
@include set-css-color-type($colors, $type);
}
生成的css变量,以primary为例子
:root {
--el-color-primary: #409eff;
--el-color-primary-light-3: #79bbff;
--el-color-primary-light-5: #a0cfff;
--el-color-primary-light-7: #c6e2ff;
--el-color-primary-light-8: #d9ecff;
--el-color-primary-light-9: #ecf5ff;
--el-color-primary-dark-2: #337ecc;
}
四、组件级使用------以el-button为例子
位置:packages/theme-chalk/src/button.scss
js
// generate css var from existing css var
// for example:
// @include css-var-from-global(('button', 'text-color'), ('color', $type))
// --el-button-text-color: var(--el-color-#{$type});
@mixin css-var-from-global($var, $gVar) {
$varName: joinVarName($var);
$gVarName: joinVarName($gVar);
#{$varName}: var(#{$gVarName});
}
==========================================================
$button-color-types 是一个 SCSS 变量(map),定义在 button-variant mixin 内部。它是一个嵌套的 map,用于定义按钮在不同状态下的颜色映射关系。
$button-color-types: (
'': (
'text-color': (
'color',
'white',
),
'bg-color': (
'color',
$type,
),
'border-color': (
'color',
$type,
),
'outline-color': (
'color',
$type,
'light-5',
),
'active-color': (
'color',
$type,
'dark-2',
),
),
'hover': (
'text-color': (
'color',
'white',
),
'link-text-color': (
'color',
$type,
'light-5',
),
'bg-color': (
'color',
$type,
'light-3',
),
'border-color': (
'color',
$type,
'light-3',
),
),
'active': (
'bg-color': (
'color',
$type,
'dark-2',
),
'border-color': (
'color',
$type,
'dark-2',
),
),
'disabled': (
'text-color': (
'color',
'white',
),
'bg-color': (
'color',
$type,
'light-5',
),
'border-color': (
'color',
$type,
'light-5',
),
),
);
// 结构层次
$button-color-types (第一层:状态)
├─ '' (默认状态)
│ ├─ 'text-color' → ('color', 'white')
│ ├─ 'bg-color' → ('color', $type)
│ ├─ 'border-color' → ('color', $type)
│ ├─ 'outline-color' → ('color', $type, 'light-5')
│ └─ 'active-color' → ('color', $type, 'dark-2')
│
├─ 'hover' (悬停状态)
│ ├─ 'text-color' → ('color', 'white')
│ ├─ 'link-text-color' → ('color', $type, 'light-5')
│ ├─ 'bg-color' → ('color', $type, 'light-3')
│ └─ 'border-color' → ('color', $type, 'light-3')
│
├─ 'active' (激活状态)
│ ├─ 'bg-color' → ('color', $type, 'dark-2')
│ └─ 'border-color' → ('color', $type, 'dark-2')
│
└─ 'disabled' (禁用状态)
├─ 'text-color' → ('color', 'white')
├─ 'bg-color' → ('color', $type, 'light-5')
└─ 'border-color' → ('color', $type, 'light-5')
================================================================
@each $type, $typeMap in $button-color-types {
// 内层循环,遍历第二层(属性):text-color, bg-color, border-color, outline-color, active-color
// $typeColor:属性名,例如:'text-color'
// $list:属性值,例如:('color', 'white')
@each $typeColor, $list in $typeMap {
// 调用 css-var-from-global 生成 CSS 变量
// 例如:@include css-var-from-global(('button', 'hover', 'text-color'), ('color', 'white'));
@include css-var-from-global(('button', $type, $typeColor), $list);
}
}
// 当 $type = 'primary' 时,会生成:
/* 默认状态 */
--el-button-text-color: var(--el-color-white);
--el-button-bg-color: var(--el-color-primary);
--el-button-border-color: var(--el-color-primary);
--el-button-outline-color: var(--el-color-primary-light-5);
--el-button-active-color: var(--el-color-primary-dark-2);
/* 悬停状态 */
--el-button-hover-text-color: var(--el-color-white);
--el-button-hover-link-text-color: var(--el-color-primary-light-5);
--el-button-hover-bg-color: var(--el-color-primary-light-3);
--el-button-hover-border-color: var(--el-color-primary-light-3);
/* 激活状态 */
--el-button-active-bg-color: var(--el-color-primary-dark-2);
--el-button-active-border-color: var(--el-color-primary-dark-2);
/* 禁用状态 */
--el-button-disabled-text-color: var(--el-color-white);
--el-button-disabled-bg-color: var(--el-color-primary-light-5);
--el-button-disabled-border-color: var(--el-color-primary-light-5);
=====================================================================
完整源码:
@mixin button-variant($type) {
$button-color-types: (
'': (
'text-color': (
'color',
'white',
),
'bg-color': (
'color',
$type,
),
'border-color': (
'color',
$type,
),
'outline-color': (
'color',
$type,
'light-5',
),
'active-color': (
'color',
$type,
'dark-2',
),
),
'hover': (
'text-color': (
'color',
'white',
),
'link-text-color': (
'color',
$type,
'light-5',
),
'bg-color': (
'color',
$type,
'light-3',
),
'border-color': (
'color',
$type,
'light-3',
),
),
'active': (
'bg-color': (
'color',
$type,
'dark-2',
),
'border-color': (
'color',
$type,
'dark-2',
),
),
'disabled': (
'text-color': (
'color',
'white',
),
'bg-color': (
'color',
$type,
'light-5',
),
'border-color': (
'color',
$type,
'light-5',
),
),
);
// 外层循环,遍历第一层(状态):'', 'hover', 'active', 'disabled'
// $type状态名例如'hover';
// $typeMap:状态对应的属性值,例如:('text-color': (
// 'color',
// 'white',
// ),)
@each $type, $typeMap in $button-color-types {
// 内层循环,遍历第二层(属性):text-color, bg-color, border-color, outline-color, active-color
// $typeColor:属性名,例如:'text-color'
// $list:属性值,例如:('color', 'white')
@each $typeColor, $list in $typeMap {
// 调用 css-var-from-global 生成 CSS 变量
// 例如:@include css-var-from-global(('button', 'hover', 'text-color'), ('color', 'white'));
@include css-var-from-global(('button', $type, $typeColor), $list);
}
}
&.is-plain,
&.is-text,
&.is-link {
@include button-plain($type);
}
}
五、应用样式(最终渲染)
位置:packages/theme-chalk/src/button.scss
js
@include b(button) {
display: inline-flex;
justify-content: center;
align-items: center;
line-height: 1;
// min-height will expand when in flex
height: map.get($input-height, 'default');
white-space: nowrap;
cursor: pointer;
color: getCssVar('button', 'text-color');
text-align: center;
box-sizing: border-box;
outline: none;
transition: 0.1s;
font-weight: getCssVar('button', 'font-weight');
user-select: none;
vertical-align: middle;
-webkit-appearance: none;
background-color: getCssVar('button', 'bg-color');
border: getCssVar('border');
border-color: getCssVar('button', 'border-color');
&:hover {
color: getCssVar('button', 'hover', 'text-color');
border-color: getCssVar('button', 'hover', 'border-color');
background-color: getCssVar('button', 'hover', 'bg-color');
outline: none;
}
// 这些生成el-button的基础变量
======================================================
@each $type in (primary, success, warning, danger, info) {
@include m($type) {
@include button-variant($type);
}
}
// $type = 'primary' 时,最终编译后的 CSS(.el-button--primary):
.el-button--primary {
/* 基础样式 */
display: inline-flex;
justify-content: center;
align-items: center;
/* 颜色(使用 CSS 变量) */
color: var(--el-button-text-color);
/* ↓ 展开为 */
color: var(--el-color-white); /* #ffffff */
background-color: var(--el-button-bg-color);
/* ↓ 展开为 */
background-color: var(--el-color-primary); /* #409eff */
border-color: var(--el-button-border-color);
/* ↓ 展开为 */
border-color: var(--el-color-primary); /* #409eff */
}
.el-button--primary:hover {
background-color: var(--el-button-hover-bg-color);
/* ↓ 展开为 */
background-color: var(--el-color-primary-light-3); /* #79bbff */
border-color: var(--el-button-hover-border-color);
/* ↓ 展开为 */
border-color: var(--el-color-primary-light-3); /* #79bbff */
}
.el-button--primary:active {
background-color: var(--el-button-active-bg-color);
/* ↓ 展开为 */
background-color: var(--el-color-primary-dark-2); /* #337ecc */
border-color: var(--el-button-active-border-color);
/* ↓ 展开为 */
border-color: var(--el-color-primary-dark-2); /* #337ecc */
}
六、完整流程图
js
┌─────────────────────────────────────────────────────────┐
│ 阶段 1: 基础颜色定义 │
│ var.scss: primary.base = #409eff │
└─────────────────┬───────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 阶段 2: 自动生成颜色变体 │
│ set-color-mix-level() │
│ - primary.light-3 = #79bbff (30% 白色混合) │
│ - primary.dark-2 = #337ecc (20% 黑色混合) │
└─────────────────┬───────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 阶段 3: 生成全局 CSS 变量 │
│ var.scss: :root { │
│ --el-color-primary: #409eff │
│ --el-color-primary-light-3: #79bbff │
│ --el-color-primary-dark-2: #337ecc │
│ } │
└─────────────────┬───────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 阶段 4: 按钮组件使用颜色 │
│ button-variant('primary') │
│ 生成组件级 CSS 变量: │
│ --el-button-bg-color: var(--el-color-primary) │
│ --el-button-hover-bg-color: var(--el-color-primary-light-3)│
│ --el-button-active-bg-color: var(--el-color-primary-dark-2)│
└─────────────────┬───────────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ 阶段 5: 最终渲染 │
│ .el-button--primary { │
│ background-color: var(--el-button-bg-color); │
│ /* 浏览器解析为 #409eff */ │
│ } │
└─────────────────────────────────────────────────────────┘
七、优势
- 统一管理:所有颜色在一个地方定义。
- 自动计算:light/dark 变体自动生成。
- 易于定制:修改基础色即可影响所有变体和组件。
- 性能:使用 CSS 变量,支持运行时动态切换主题。