@property必须写在:root或@layer顶层,否则被静默忽略;syntax与initial-value必须严格匹配类型,否则变量无法参与transition或@keyframes动画。

@property 必须写在 :root 或 @layer 顶层,否则整条规则被浏览器静默忽略,变量无法参与动画或过渡。
必须写在 :root 或 @layer 顶层
很多人把 @property 塞进选择器里,比如 .card { @property --size {} },结果发现 transition: --size 0.3s 完全没反应——控制台也没报错,只是不动。这不是 bug,是规范强制要求:@property 是向 CSS 引擎注册全局类型契约,不能局部声明。
正确位置只有两个:
-
:root根元素下(最常用) -
@layer base { @property ... }这类未嵌套的@layer块顶层
用 @import 引入的 CSS 文件里写了 @property,也得确保它没被包裹在任何选择器内。
立即学习“前端免费学习笔记(深入)”;
syntax 和 initial-value 必须严格匹配类型
syntax 不是装饰项,它是解析开关。一旦不匹配,浏览器连 initial-value 都不读,整条规则被丢弃,后续所有 var(--x) 都退化为纯字符串变量。
典型错误示例:
-
syntax: "<color>"却写initial-value: 0→ 失效(数字不是颜色) -
syntax: "<number>"却写initial-value: "10"→ 失效(带引号的字符串) -
syntax: "<length>"写initial-value: 10(缺单位)→ 失效(必须是10px或1em)
用 syntax: "*" 最宽松,但会放弃类型校验,插值可能中断(比如单位缺失时直接 fallback 到字符串混合)。
颜色类型必须用 syntax: "<color>" 才能启用插值
没注册 @property 的 --theme-color,哪怕你赋值 red 和 #fff,transition: --theme-color 0.3s 也不会动——浏览器把它当两个字符串,中间没法算帧。
注册后:
-
syntax: "<color>"告诉浏览器:只接受合法颜色值,非法值(如--theme-color: 123)会被静默忽略,回退到initial-value - 浏览器获得颜色插值能力,
red → #e74c3c才能平滑过渡 - 必须显式写
inherits: false或inherits: true,否则语法错误
注意:background: var(--theme-color) 可以直接用;但像 rotate: var(--deg) 这种数值上下文,Chromium 目前仍要求加 calc() 包裹,例如 rotate: calc(var(--deg) * 1)。
渐变动画要拆成多个注册属性
浏览器不支持对整个 linear-gradient() 字符串做插值。想实现渐变色平滑变化,得把起点色、终点色、角度等拆开注册:
@property --start-color { syntax: "<color>"; inherits: false; initial-value: #667eea; }@property --end-color { syntax: "<color>"; inherits: false; initial-value: #764ba2; }@property --gradient-angle { syntax: "<angle>"; inherits: false; initial-value: 135deg; }
然后在样式中组合:background: linear-gradient(var(--gradient-angle), var(--start-color), var(--end-color));
这样每部分都有类型约束,插值才可控。直接对 --full-gradient 注册并赋值两个不同 linear-gradient() 字符串,依然不会动。
真正容易被忽略的是:即使所有语法都对了,如果目标浏览器不支持(比如 Safari 16.6 之前),@property 规则也会被跳过,且无任何提示。上线前务必查 CanIUse 数据,并准备降级方案——比如用伪元素 + opacity 动画模拟渐变切换。


















