CSS 自定义属性(也称为 CSS 变量)从根本上改变了我们编写和维护样式表的方式。与 Sass 或 Less 中的预处理器变量不同,自定义属性是实时的、动态的,并且参与级联和继承。本文探讨了在生产应用程序中使用它们的战略模式——从设计令牌管理到运行时操作。
设计代币管理
自定义属性是设计令牌的理想载体——定义设计系统视觉语言的原子值。组织良好的标记结构按照清晰的命名约定对颜色、间距、版式和阴影进行分组。
:root {
--color-primary-500: #3b82f6;
--color-primary-700: #1d4ed8;
--space-xs: 0.25rem;
--space-md: 1rem;
--space-xl: 2rem;
--font-sans: "Inter", system-ui, sans-serif;
--text-base: 1rem;
--text-lg: 1.25rem;
--shadow-sm: 0 1px 2px rgb(0 0 0 / 0.05);
}
采用受 BEM 启发的命名空间命名约定:对于组件标记使用 --block__element--modifier,对于全局标记使用 --category-property-variant。这使得令牌树保持可预测和自记录。
主题切换
自定义属性使运行时主题切换变得简单。在 :root 上定义浅色主题,并覆盖深色主题选择器下的特定标记。
:root {
--bg: #ffffff;
--text: #111111;
--border: #e5e7eb;
}
[data-theme="dark"] {
--bg: #111111;
--text: #f3f4f6;
--border: #374151;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #111111;
--text: #f3f4f6;
}
}
body {
background: var(--bg);
color: var(--text);
}
使用 transition: background-color 0.3s 添加主题之间的平滑过渡,并将用户的首选项保留在 localStorage 中。这种方法可以扩展到多个主题——浅色、深色、高对比度和棕褐色——而无需重复组件样式。
使用 JavaScript 进行运行时操作
自定义属性的最大优点之一是能够在运行时读取和修改它们,而无需任何 CSS-in-JS 库。
const root = document.documentElement;
root.style.setProperty("--spacing", `${userSpacing}px`);
const currentSpacing = getComputedStyle(root).getPropertyValue("--spacing");
这使得用户可以控制字体大小、基于上传图像的动态颜色主题、滚动驱动的动画以及响应容器查询的值。该 API 在所有现代浏览器中都是一致的,并且依赖性开销为零。
继承模式
自定义属性通过 DOM 树级联,无需重复样式即可实现上下文覆盖。
.card {
--card-padding: 1rem;
--card-radius: 0.5rem;
}
.card.featured {
--card-padding: 2rem;
--card-radius: 1rem;
}
.card__body {
padding: var(--card-padding);
border-radius: var(--card-radius);
}
当未定义属性时,使用 var(--custom, fallback) 提供默认值。在 Shadow DOM 中,自定义属性穿透 Shadow 边界,使它们成为主题 Web 组件的标准机制。
预处理器集成
自定义属性和预处理器起到互补作用。预处理器擅长编译时任务,例如数学和混合;自定义属性在运行时动态方面表现出色。
$grid-columns: 12;
$breakpoint-md: 768px;
:root {
--color-primary: #{$primary-hex};
--grid-gap: 1rem;
}
.container {
max-width: $breakpoint-md;
column-gap: var(--grid-gap);
}
| 特色 | 预处理器变量 | CSS 自定义属性 |
|---|---|---|
| 决议时机 | 构建时间 | 运行时 |
| 级联 | 没有 | 是的 |
| DOM 继承 | 没有 | 是的 |
| 数学运算 | 本地 | 需要 calc() |
| 动画 | 没有 | 是的 |
性能考虑因素
自定义属性在计算值时解析,而不是在解析期间解析。实际上,在 :root 上定义数百个标记的影响可以忽略不计。但是,请避免在 calc() 内对触发热动画路径中的布局的属性使用自定义属性。在动画较多的部分使用 contain: style paint layout 来限制重新计算范围。
后备策略
对于旧版浏览器支持,请使用带有后备值的渐进增强。
.element {
color: #333333;
color: var(--text-color, #333333);
}
使用 @supports (--custom: property) 的功能查询可以控制高级使用,PostCSS 插件可以在构建时编译具有回退功能的自定义属性。到 2024 年,全球支持率将超过 97%,因此主要需要针对利基企业环境进行回退。
CSS 自定义属性不再是新鲜事——它们是构建可扩展、可维护样式表的基本工具。它们策略性地与设计标记、主题切换和运行时操作一起使用,消除了整个类别的样式问题。

