如何用SCSS变量高效定制TDesign主题?

5 人参与

在大型企业后台系统里,品牌色、圆角、阴影等视觉要素往往需要随业务线快速切换。直接在 CSS 中手动改写既容易出错,又会让样式体积膨胀。SCSS 变量提供了“一改全改”的路径,只要在主题入口统一声明几组关键变量,后续所有组件都会实时映射,从而实现“写一次、用遍全局”。

SCSS 变量的组织原则

变量不宜盲目堆砌,而应围绕设计令牌(Design Token)分层管理:全局色板品牌语义色尺寸尺度交互状态衍生。全局色板仅保留基础 hue、saturation、lightness,品牌语义色在此基础上通过函数生成 hover、active、disabled 等变体;尺寸尺度则用 $spacing-base$radius-base 等基准值做比例扩展。这样一来,修改品牌主色只需要改动一行变量,衍生色会在编译时自动推算。

  • 变量命名遵循 td- 前缀,避免与业务变量冲突。
  • 所有变量统一放在 src/styles/tokens/_variables.scss
  • 颜色使用 hsla(),便于在函数中调节透明度。
  • 尺寸采用 rem,配合根字体大小实现响应式。
// src/styles/tokens/_variables.scss
$td-primary-h: 210;
$td-primary-s: 78%;
$td-primary-l: 56%;

$td-primary: hsla($td-primary-h, $td-primary-s, $td-primary-l, 1);
$td-primary-hover: hsla($td-primary-h, $td-primary-s, $td-primary-l + 5%, 1);
$td-primary-active: hsla($td-primary-h, $td-primary-s, $td-primary-l - 5%, 1);

$td-border-radius: 0.5rem;
$td-spacing-base: 0.75rem;

从根文件到组件的覆盖路径

main.scss 中先引入变量文件,再全局引入 TDesign 的核心样式;随后通过 @use 语法把变量注入组件的 SCSS。TDesign 的内部实现会在编译阶段读取 var(--td-…),而我们提前用 --td-… 映射到自定义的 SCSS 变量,等价于一次性覆盖所有组件的 CSS 变量。

// src/main.scss
@use 'styles/tokens/variables' as *;
@import '~tdesign-vue-next/lib/style/index.scss';

// 只在需要时覆盖局部变量
.td-button {
  --td-primary-color: #{$td-primary};
  --td-primary-hover-color: #{$td-primary-hover};
}

提升编译效率的技巧

SCSS 编译本身并不是瓶颈,真正拖慢构建的是重复的文件遍历。建议使用 vite-plugin-sass-dts 生成类型声明,配合 Vite 的缓存层;同时把变量文件标记为 sideEffects: false,让 webpack/rollup 在生产模式下剔除未引用的变量块。这样即使主题变量多达数百行,也能保持首屏加载在 1.2 秒以内。

实战案例:快速切换品牌色

假设产品即将在同一天上线两个子品牌,只需在 CI 脚本里传入环境变量 BRAND=alpha,再用 Node 脚本改写 _variables.scss 中的 $td-primary-h$td-primary-s$td-primary-l 三个值。构建完成后,两个产物分别对应不同的主色,且组件内部的 hover、active、disabled 都已自动适配。整个流程从手工改代码到一键构建,时间从半天跌至几分钟。

参与讨论

5 条评论
  • Dark小暗影

    SCSS变量确实让主题定制方便多了,我们项目最近也在用

  • 云端哲人

    这种颜色分层管理的方式挺实用的,不过想问下在IE11上有兼容问题吗?

  • 绿豆糕

    变量命名加td-前缀的做法学到了,之前项目里就经常跟业务变量冲突😅

  • 我是大聪明

    编译速度优化那块很有用,我们项目现在构建确实有点慢

  • 墨染狂想

    用环境变量切换主题这个方案不错,正好最近要搞多品牌部署