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

CSS变量命名必须带命名空间前缀
裸名如 --color 或 --sm 在大型项目里等于埋雷。不同模块、不同人写的变量一旦撞名,DevTools 里查不到来源,构建后也难定位。Bilibili-Evolved 的 --be-、--ui-、--video- 前缀不是为了好看,是强制隔离作用域。
实操建议:
- 按功能维度定一级前缀:
--color-、--space-、--radius-、--shadow-,不写--main-color这类模糊名 - 二级语义补全,比如
--color-text-primary而非--text-primary,避免和 JS 中的textPrimary变量混淆 - 组件级变量挂到组件根节点,用
--ui-button-而非全局--button-,防止污染其他 block
变量名与BEM类名要形成映射关系,但不混用层级
--ui-button__text--large-size 看起来“很BEM”,但这是错的。CSS变量不继承BEM的 __ / -- 语法结构,强行套用只会让 IDE 补全失效、VS Code 搜索变慢、团队新人看不懂。
正确做法是用命名空间 + 语义组合:
- 对应
.button--large,变量叫--ui-button-size-large,不是--ui-button--large - 对应
.button__icon,变量叫--ui-button-icon-size,而非--ui-button__icon - Modifier 类名(如
--disabled)仍保留,但它的样式值由变量驱动:opacity: var(--ui-button-opacity-disabled)
避免用变量替代状态类名
--is-hovered、--is-open 这类布尔型变量是反模式。CSS自定义属性适合管“值”,不适合管“状态”。状态变化应靠 class 控制,变量只负责把值注入进去。
常见错误现象:
- JS 动态设置
el.style.setProperty('--is-active', 'true'),然后在 CSS 里写@media (prefers-reduced-motion) { [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); }
变量注入时机决定维护成本
所有变量必须由构建时或 JS 初始化阶段注入,不能靠人工维护多套 CSS 文件。比如深色模式切换,不要写两份 :root,而应统一声明 --ui-button-bg,再由 JS 根据主题动态赋值。
容易踩的坑:
- 在 SCSS 中用
$map生成变量,但没导出为 CSS Custom Properties,导致 JS 无法读取 - 把变量写在组件 scoped style 里,结果
:root中缺失,跨组件复用失败 - 未加 fallback:
color: var(--color-text-primary, #333);缺失时直接回退,别留空值
复杂点在于:变量既要支持设计系统级别的统一控制,又要允许局部覆盖。最稳的方式是三层作用域 —— :root(全局)、组件根元素(.card)、伪类或 modifier(.card--featured),逐层 var() 覆盖,而不是堆砌 !important 或嵌套 selector。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











