css变量命名必须带功能前缀(如--color-、--space-)并禁用裸名,按作用域分层管理,组件级用--ui-button-等隔离,变量管值不管状态,须设fallback且统一注入。

变量名必须带功能前缀,禁用裸名
裸名如 --color 或 --sm 在大型项目里等于埋雷。不同模块、不同人写的变量一旦撞名,DevTools 里查不到来源,构建后也难定位。Bilibili-Evolved 的 --be-、--ui-、--video- 前缀不是为了好看,是强制隔离作用域。
实操建议:
- 按功能维度定一级前缀:
--color-、--space-、--radius-、--shadow-,不写--main-color这类模糊名 - 二级语义补全,比如
--color-text-primary而非--text-primary,避免和 JS 中的textPrimary变量混淆 - 所有变量必须设 fallback:
color: var(--color-text-primary, #333),且统一注入到:root或组件根节点
组件级变量要挂到组件根节点,不污染全局
用 --ui-button- 而非全局 --button-,否则按钮变量可能意外影响表单、卡片甚至第三方 UI 库里的同名元素。
常见错误现象:
- 在
:root定义--button-bg,结果弹窗里的确认按钮也跟着变色 - 多个组件共用
--size-md,但各自对“中等尺寸”的理解不一致(8px vs 12px)
正确做法:
- 组件根节点加 class 后定义变量,例如
.ui-button { --ui-button-bg: var(--color-surface-default); } - 变量名与 BEM 类名形成映射但不套语法:
.button--large对应--ui-button-size-large,而非--ui-button--large - Modifier 类(如
.button--disabled)仍保留,它内部用变量驱动:.button--disabled { background-color: var(--ui-button-bg-disabled); }
避免用变量替代状态类名
--is-hovered、--is-open 这类布尔型变量是反模式。CSS 自定义属性适合管“值”,不适合管“状态”。状态变化应靠 class 控制,变量只负责把值注入进去。
容易踩的坑:
- JS 动态设置
el.style.setProperty('--is-active', 'true'),然后在 CSS 里写[style*="--is-active:true"]—— 不可靠、不可调试、无法被 PurgeCSS 识别 - 用
data-属性配合变量做开关,比如[data-state="loading"] { --ui-button-bg: var(--color-surface-disabled); }—— 绕过 class 系统,破坏 BEM 的“类名即契约”原则
应该怎么做:
- 保持
.button--loading类名存在,它内部用变量:.button--loading { background-color: var(--ui-button-bg-loading); } - 状态切换走 class 切换,变量只承载视觉值,不参与逻辑判断
命名空间需与构建/注入时机对齐
变量注入时机决定维护成本。所有变量必须由构建时或 JS 初始化阶段注入,不能靠人工维护多套 CSS 文件。
vanilla-extract 等零运行时方案中,推荐用嵌套对象组织变量,例如:
export const vars = createGlobalTheme(':root', {
colors: {
backgroundColor: 'blue',
text: 'white',
},
space: {
1: '4px',
2: '8px',
},
});
这样生成的 CSS 变量自动带命名空间前缀,且 IDE 补全、VS Code 搜索、团队协作都更稳定。手动拼接字符串或靠注释约定前缀,很快就会失效。
最常被忽略的一点:变量名一旦上线,就很难安全重命名——CSS 变量没有引用追踪能力,改名等于全局搜索替换 + 全链路回归测试。所以第一次命名就得想清楚层级和语义边界。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











