CSS Handbook · 自定义属性与现代函数

第十章 / 10.1 CSS 自定义属性

第十章 · 10.1 节

CSS 自定义属性


自定义属性(俗称 CSS 变量)让"魔法数字"和重复的颜色值有了统一的出处。本教程站点的配色系统——纸张色、墨色、强调色,全部通过 :root 上的自定义属性定义,深浅色模式切换本质上就是重新赋值这些变量。

声明与使用

:root {
  --accent: #8a5a2e;
  --gap: 16px;
}
.btn {
  color: var(--accent);
  padding: var(--gap);
}

自定义属性以 -- 开头,取值可以是任意合法 CSS 片段,通过 var() 函数读取。它们区分大小写,且不会被浏览器做任何语法校验(直到被 var() 实际使用时才检查)。

自定义属性也会层叠,且可继承

与普通属性一样,自定义属性遵循层叠与继承规则——这正是它比 Sass 变量强大的地方:Sass 变量在编译时就被替换为固定值,而 CSS 变量在运行时按 DOM 树逐层生效,可以被任意层级的选择器覆盖。

.theme-warm { --accent: #b3452c; }
/* .theme-warm 内部所有引用 --accent 的元素,颜色自动切换,无需重复声明 */
效果预览:局部覆盖变量
默认 --accent
局部覆盖后

回退值

var() 的第二个参数是回退值,当变量未定义时生效,让组件在脱离主题上下文时也不至于样式崩坏:

.badge {
  background: var(--badge-color, #3f5d54);
}

与 JavaScript 联动

自定义属性可以被 JavaScript 读写,是连接样式系统与交互逻辑的桥梁,无需再用内联 style 拼接一长串样式字符串:

el.style.setProperty('--progress', '64%');
.bar::before {
  width: var(--progress, 0%);
  transition: width .3s ease;
}

@property:为变量声明类型

普通自定义属性的值在浏览器眼中只是一段"未经解析的文本",因此无法参与过渡动画(比如渐变角度、颜色不能平滑过渡)。@property 让我们显式声明变量的类型、初始值与是否可继承,赋予它真正参与插值计算的能力:

@property --angle {
  syntax: '<angle>';
  inherits: false;
  initial-value: 0deg;
}
.spin {
  background: conic-gradient(#8a5a2e var(--angle), #e7e8e1 0);
  transition: --angle .3s ease;
}
.spin:hover { --angle: 360deg; }

实践:设计令牌

大型项目中,建议把自定义属性组织为分层的"设计令牌"体系:底层是原始色值/间距(primitive),上层是带语义的别名(semantic),组件样式只引用语义层,替换主题时只需改动上层映射:

/* 原始层 */
:root { --brown-600: #8a5a2e; --teal-600: #3f5d54; }

/* 语义层:组件只认这一层 */
:root {
  --color-accent: var(--brown-600);
  --color-success: var(--teal-600);
}