CSS 自定义属性实战:从换肤到组件设计
最近给项目加深色模式,趁机把 CSS 自定义属性(CSS Custom Properties,俗称 CSS 变量)用了一遍。用下来最大的感受:它和 Sass 变量根本不是一回事,能力边界完全不同。
基本语法
声明在 -- 开头的属性上,用 var() 引用:
:root {
--primary-color: #409eff;
--radius: 4px;
}
.button {
background: var(--primary-color);
border-radius: var(--radius);
}
var() 支持兜底值,多级兜底也可以:
.title {
/* --title-color 不存在就用 --text-color,再不行就用 #333 */
color: var(--title-color, var(--text-color, #333));
}
注意一个坑:无效值不会回退到兜底,而是变成"未设置"。
:root {
--size: 20px;
}
.box {
--size: banana; /* 无效但语法上会被接受 */
width: var(--size, 50px); /* 最终 width 是 unset,不是 50px! */
}
这是 CSS 变量最让人迷惑的行为,排查时留意。
和 Sass 变量的本质区别
很多人(包括曾经的我)以为 CSS 变量就是"Sass 变量的浏览器版",其实两者的运行机制完全不同:
| Sass 变量 | CSS 变量 | |
|---|---|---|
| 生效时机 | 编译时,替换完就没了 | 运行时,真实存在于 DOM |
| JS 能否读写 | 不能 | 能 |
| 能否响应媒体查询 | 不能 | 能 |
| 作用域 | 文件级 | 跟随 DOM 树层叠 |
运行时存在这一点,是 CSS 变量的杀手锏。
实战一:零 JS 的响应式变量
变量本身可以跟随媒体查询变化,消费方完全无感:
:root {
--content-width: 1200px;
--font-size: 16px;
}
@media (max-width: 768px) {
:root {
--content-width: 100%;
--font-size: 14px;
}
}
.container {
max-width: var(--content-width);
font-size: var(--font-size);
}
业务代码里一处 var(),样式在两端自动切换,比写一堆媒体查询覆盖干净多了。
实战二:JS 驱动的主题切换
读写 CSS 变量的 API 很直白:
// 读取
const color = getComputedStyle(document.documentElement)
.getPropertyValue('--primary-color')
// 写入
document.documentElement.style.setProperty('--primary-color', '#67c23a')
配合 class 切换,一套完整的换肤方案长这样:
/* 默认(浅色)主题 */
:root {
--bg: #ffffff;
--text: #303133;
}
/* 深色主题 */
.dark {
--bg: #1a1a1a;
--text: #e4e7eb;
}
body {
background: var(--bg);
color: var(--text);
transition: background 0.3s, color 0.3s;
}
// 切换主题就是切一个 class
document.documentElement.classList.toggle('dark')
变量层叠覆盖 + 一个 class 切换,所有用了 var(--bg) 的地方瞬间换装。这就是 Element Plus 2.x 之后采用的方案(它们 1.x 时代还是编译多套 CSS 文件,体积巨大)。
实战三:组件样式的"开口"
写通用组件时,CSS 变量是留定制口的绝佳方式:
.card {
padding: var(--card-padding, 16px);
box-shadow: var(--card-shadow, 0 2px 8px rgba(0, 0, 0, 0.1));
}
使用方不用 hack 内部结构,直接在外层覆盖变量:
.marketing-page .card {
--card-padding: 32px;
--card-shadow: 0 8px 24px rgba(0, 0, 0, 0.15);
}
比 ::v-deep 穿透、比 !important 都优雅,还保持了组件的封装性。
小结
- CSS 变量是运行时特性,能响应媒体查询、能被 JS 读写——这是它和 Sass 变量的本质区别
var()的兜底只在变量不存在时生效,无效值不会回退- 主题切换:变量定义在 :root / .dark,切 class 即可
- 组件定制:默认值写在 var() 里,使用方从外层覆盖变量
新项目里我的建议是:Sass 变量管"编译期常量"(断点值、mixin 参数),CSS 变量管"运行时可变的主题与配置",两者配合着用。
看到这里了?如果这篇文章帮到过你
请我喝瓶可乐就好 🥤

评论0 条
还没有评论,来抢沙发~