跳到主要内容

CSS 变量提取实战:把硬编码颜色尺寸抽成自定义属性

教你从旧样式表里提取 CSS 自定义属性,把散落的颜色和尺寸抽成设计令牌,并顺手接上暗黑模式主题切换,重构起来不再翻文件。

发布于 作者 李雷
#CSS #设计令牌 #暗黑模式 #重构

CSS 变量提取实战:把硬编码颜色尺寸抽成自定义属性

接手一份写了三四年的样式表,最先让我头疼的不是布局,而是颜色。同一个蓝色,有人写 #1a73e8,有人写 rgb(26, 115, 232),还有人手抖打成 #1a72e8,肉眼根本看不出差别。尺寸也一样,16px1rem0.875em 混在一起,改一处主色得全局搜十几遍。CSS 自定义属性(也就是大家常说的 CSS 变量)就是为收拾这种烂摊子准备的,而提取这一步,是整场重构的起点。

CSS 变量到底解决了什么

CSS 自定义属性以 -- 开头声明,用 var() 引用。一个最朴素的例子:

:root {
  --color-primary: #1a73e8;
  --space-md: 16px;
}
.btn {
  background: var(--color-primary);
  padding: var(--space-md);
}

声明集中在 :root,引用散落在各处。改主色只动 --color-primary 一行,全站跟着变。它和 Sass 变量最大的区别是运行时生效,浏览器随时能读到当前值,这正是后面做主题切换的底气。重构旧样式表的第一件事,就是把那些写死的 #1a73e816px 找出来,归拢成一份变量清单。

从旧样式表里提取变量清单

手动翻文件找变量声明效率太低,尤其是几千行的编译产物。我习惯把样式表整段粘进 CSS 变量提取器,它在浏览器本地扫描 -- 开头的自定义属性,丢掉选择器和注释,只留下变量名,还带行号和去重。

举个真实的输入。假设我从一份组件库里复制出这么一段:

:root {
  --color-primary: #1a73e8;
  --color-primary: #1a73e8;
  --color-danger: #e53935;
  --radius-sm: 4px;
  --space-md: 16px;
}
.card { --shadow-1: 0 1px 3px rgba(0,0,0,.12); }

提取后得到的清单是这样:

--color-primary   (行 2,重复已合并)
--color-danger    (行 4)
--radius-sm       (行 5)
--space-md        (行 6)
--shadow-1        (行 7)

--color-primary 声明了两次,提取器自动合并成一行并标出重复,省得我自己核对。拿到这份清单,我就知道这套样式一共定义了哪些令牌,哪些是颜色、哪些是间距、哪些是阴影,重构时心里有数。

把硬编码值抽成设计令牌

提取只是第一步,真正的重构是把散落的硬编码值反向收敛成令牌。我的做法分三轮。

第一轮收颜色:全局搜 #rgbhsl,把出现两次以上的值提成 --color-*。第二轮收尺寸:pxrem 里反复出现的几个数值,归成 --space-*--radius-* 的阶梯。第三轮收语义:把 --color-primary 这种偏底层的,再包一层 --btn-bg: var(--color-primary),让组件引用语义令牌而不是直接咬住色值。

设计令牌的价值就在这层语义。设计师说「主按钮换个绿」,我只改 --color-primary,不用关心哪个按钮用了它。如果颜色值本身格式混乱,可以先过一遍 HEX 颜色校验,把 #1a72e8 这类打错一位的脏值挑出来,避免把错误一起抽成令牌。

顺手接上暗黑模式

变量抽干净后,暗黑模式几乎是白送的。核心思路是同一组变量名,在不同主题下给不同值:

:root {
  --bg: #ffffff;
  --text: #1f1f1f;
}
[data-theme="dark"] {
  --bg: #121212;
  --text: #e8e8e8;
}
body {
  background: var(--bg);
  color: var(--text);
}

所有组件引用的是 var(--bg)var(--text),切主题只是切换 data-theme 属性,浏览器即时重算,不用改任何组件代码。这也是我坚持先把硬编码抽成变量的原因:没有这层间接,暗黑模式就得逐个组件改样式,工作量翻倍还容易漏。

维护一份令牌台账

提取出的变量清单不该一次性用完就扔。我会把它导出成 CSV 或 Markdown,连同行号一起存进仓库,当作令牌台账。下次有人新增了一个 --color-accent,对照台账就能发现它和已有的 --color-primary 是不是同一个值、要不要合并。提取器支持导出 JSON、Markdown 这些格式,接进文档或脚本都顺手。

回头看,CSS 变量提取不是个孤立动作,而是「提取清单,反向收敛令牌,铺开主题」这条重构链路的第一环。把第一环做扎实,后面的暗黑模式、品牌换肤才不会变成体力活。


Made by Toolora · Updated 2026-06-13