CSS 变量(自定义属性)
CSS 变量(正式名称为自定义属性,Custom Properties)让你在样式表中定义可复用的值。它们比预处理器变量(如 Sass 的 $color)更强大——因为 CSS 变量是动态的,可以在运行时改变。
声明与使用
声明变量
变量名以 -- 开头,通常定义在 :root 中作为全局变量:
css
:root {
--color-primary: #2563eb;
--color-bg: #f8fafc;
--spacing-md: 1rem;
--radius: 8px;
--font-body: system-ui, sans-serif;
} 使用变量
用 var() 函数读取变量值:
css
.button {
background: var(--color-primary);
padding: var(--spacing-md);
border-radius: var(--radius);
font-family: var(--font-body);
} html
<div style="--color-primary:#2563eb;--spacing-md:0.75rem 1.5rem;--radius:6px;--font-body:system-ui,sans-serif">
<div class="button">按钮</div>
</div> 作用域
变量在其声明所在的元素及其所有后代中可用:
css
:root {
--text-color: #1e293b; /* 全局 */
}
.dark-section {
--text-color: #e2e8f0; /* 仅在此区块及其内部生效 */
background: #0f172a;
color: var(--text-color);
}
p {
color: var(--text-color); /* 在 .dark-section 内是白色,外面是黑色 */
} html
<p>我是黑色文字</p>
<div class="dark-section">
<p>我是白色文字(变量被重载了)</p>
</div> 这就是 CSS 变量比预处理器变量强大的核心原因——可以在运行时基于选择器的上下文动态改变。这在实现主题切换(dark mode)、组件变体时是杀手级特性。
回退值
var() 的第二个参数作为回退值:
css
.card {
background: var(--card-bg, white);
/* 如果 --card-bg 未定义,使用 white */
padding: var(--padding, 1rem 2rem);
} 回退值可以嵌套另一个 var():
css
.element {
/* 先尝试 --primary,没有就尝试 --blue,最后用 #2563eb */
color: var(--primary, var(--blue, #2563eb));
} 与 JavaScript 交互
CSS 变量的动态性在 JavaScript 中体现得最充分:
javascript
// 读取 CSS 变量
const primaryColor = getComputedStyle(document.documentElement)
.getPropertyValue('--color-primary');
// 设置 CSS 变量(修改全局主题色)
document.documentElement.style.setProperty('--color-primary', '#ef4444');
// 移除变量
document.documentElement.style.removeProperty('--color-primary'); 这使得主题切换变得极其简单:
css
:root {
--bg: white;
--text: #1e293b;
}
[data-theme="dark"] {
--bg: #0f172a;
--text: #e2e8f0;
}
body {
background: var(--bg);
color: var(--text);
} javascript
// 一键切换主题
function toggleTheme() {
const html = document.documentElement;
const current = html.getAttribute('data-theme');
html.setAttribute('data-theme', current === 'dark' ? 'light' : 'dark');
} 实际工程应用
设计令牌(Design Tokens)
将设计系统的所有可配置值定义为 CSS 变量,实现全站一致:
css
:root {
/* 颜色 */
--color-primary: #2563eb;
--color-primary-hover: #1d4ed8;
--color-success: #16a34a;
--color-warning: #d97706;
--color-danger: #dc2626;
/* 文字 */
--color-text: #1e293b;
--color-text-secondary: #64748b;
--color-border: #e2e8f0;
/* 间距 */
--space-xs: 0.25rem;
--space-sm: 0.5rem;
--space-md: 1rem;
--space-lg: 1.5rem;
--space-xl: 2rem;
--space-2xl: 3rem;
/* 字体 */
--font-sans: system-ui, -apple-system, sans-serif;
--font-mono: 'JetBrains Mono', 'Consolas', monospace;
/* 字号 */
--text-sm: 0.875rem;
--text-base: 1rem;
--text-lg: 1.125rem;
--text-xl: 1.25rem;
--text-2xl: 1.5rem;
--text-3xl: 1.875rem;
/* 圆角 */
--radius-sm: 4px;
--radius-md: 8px;
--radius-lg: 12px;
--radius-full: 9999px;
/* 阴影 */
--shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.05);
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.07);
--shadow-lg: 0 10px 15px rgba(0, 0, 0, 0.1);
} 组件变体
css
.btn {
--btn-bg: var(--color-primary);
--btn-color: white;
background: var(--btn-bg);
color: var(--btn-color);
padding: var(--space-sm) var(--space-lg);
border-radius: var(--radius-md);
}
/* 变体:修改局部变量 */
.btn-danger {
--btn-bg: var(--color-danger);
}
.btn-ghost {
--btn-bg: transparent;
--btn-color: var(--color-primary);
border: 1px solid var(--color-primary);
} html
<div style="--color-primary:#2563eb;--color-danger:#ef4444;--space-sm:0.5rem;--space-lg:1.5rem;--radius-md:6px">
<button class="btn">默认按钮</button>
<button class="btn btn-danger">危险按钮</button>
<button class="btn btn-ghost">幽灵按钮</button>
</div> calc() 结合变量
css
.sidebar-layout {
--sidebar-width: 250px;
display: grid;
grid-template-columns: var(--sidebar-width) 1fr;
/* 或动态计算 */
grid-template-columns: calc(var(--sidebar-width) + 2rem) 1fr;
} CSS 变量不能直接用于媒体查询——@media (min-width: var(--bp-md)) 是无效的。也不能在 url() 中直接拼接:url(var(--path)/image.png) 不会工作。
CSS 变量 vs 预处理器变量
| 特性 | CSS 变量 | Sass/Less 变量 |
|---|---|---|
| 运行时可变 | 是 | 否(编译后替换为值) |
| 作用域 | CSS 级联 | 代码块 |
| JS 可读写 | 是 | 否 |
| 可继承 | 是 | 否 |
| 媒体查询中可用 | 否 | 是(编译时) |
两者可以互补使用:预处理器变量管理编译时的常量(如数学运算、颜色函数),CSS 变量管理运行时的主题和动态值。