CSS自定义属性动画动不了?这个@property注册坑我踩了三次才摸清楚

我第一次用 –progress 做进度条动画的时候,transition 写了,hover 也加了,结果就是不动。F12 打开一看,属性值明明变了,但画面就是卡在那里。后来才知道,问题出在我没给这个自定义属性「注册类型」。

普通的自定义属性为什么做不了动画

CSS 自定义属性(CSS Variables)你肯定用过:

:root {
  --progress: 0;
}
.bar {
  width: var(--progress);
  transition: width 0.5s ease;
}
.bar:hover {
  --progress: 80%;
}

这个写法的 –progress 本质上是一个字符串,浏览器不知道它是数字、百分比还是颜色。遇到 transition 的时候,浏览器会走另一个分支——直接跳到终值,没有过渡。所以你的进度条会「啪」一下变过去,而不是顺滑地走过去。

@property 是什么

@property 是 CSS Houdini API 的一部分,允许你给自定义属性「注册」一个明确的类型。注册完之后,浏览器才知道这个属性是可以做插值计算的,从而触发 transition 和 animation。

基本写法就三行:

@property --progress {
  syntax: "<percentage>";
  inherits: false;
  initial-value: 0%;
}
  • syntax:定义值的类型,支持 <length><number><color><percentage><angle><time>
  • inherits:是否向下继承,动画场景通常 false
  • initial-value:默认值,必须和 syntax 匹配

注册完再写同样的 transition,效果就完全不一样了。

三个我踩过的坑

坑一:syntax 写错了,整个注册无效

/* 错误:颜色要用 <color>,不是引号包裹的字符串 */
@property --bg {
  syntax: "#c0ffee";  /* ❌ */
  inherits: false;
  initial-value: #c0ffee;
}

/* 正确:类型标识符写在引号外面 */
@property --bg {
  syntax: "<color>";  /* ✅ */
  inherits: false;
  initial-value: #c0ffee;
}

syntax 里引号包裹的是类型标识符,不是值本身。写错类型浏览器直接忽略整条 @property。

坑二:initial-value 和 syntax 不匹配

/* 错误:syntax 写的是 <number>,initial-value 给的是长度值 */
@property --scale {
  syntax: "<number>";
  inherits: false;
  initial-value: 1.5rem;  /* ❌ 不匹配 */
}

/* 正确:数字就写纯数字 */
@property --scale {
  syntax: "<number>";
  inherits: false;
  initial-value: 1.5;  /* ✅ */
}

Chrome DevTools 里这条属性会显示为 invalid,失去动画能力。

坑三:在 @keyframes 里改 registered 属性不生效

@property 注册的属性不能在 @keyframes 里直接插值。要做关键帧动画,得用 transition 配合状态变化,或者用 CSS Animation 但属性值得是 registered 的。

/* 这个不生效 */
@property --angle {
  syntax: "<angle>";
  inherits: false;
  initial-value: 0deg;
}

@keyframes spin {
  to { --angle: 360deg; }  /* ❌ 关键帧里改 registered 属性 */
}

/* 这个可以 */
.rotate {
  animation: spin 2s linear infinite;
  /* 需要配合实际的 transform 属性 */
}

渐变色做动画也是同样道理——你注册了 –gradient-angle,transition 渐变角度是可以动的,但要完整过渡两个渐变值本身,还是有限制。

什么场景用最划算

@property 最适合这几类场景:

  1. 进度条/加载动画:数字类型注册后直接 transition,平滑且零 JS
  2. 颜色主题切换:注册 –accent-color,hover 切换时整个网站颜色渐变过渡
  3. 角度/旋转动画:注册 <angle> 类型,做三角形旋转、光晕效果
  4. 复杂数值动画:注册 <transform-function>,做 3D 卡片倾斜跟随鼠标

一个完整例子——渐变色主题切换:

@property --hue {
  syntax: "<number>";
  inherits: false;
  initial-value: 220;
}

.card {
  background: hsl(var(--hue), 80%, 60%);
  transition: --hue 0.6s ease;
}

.card:hover {
  --hue: 340;
}

鼠标放上去,背景色就会从蓝紫色平滑过渡到红紫色,完全不用 JS。

兼容性:现在能用了

@property 从 July 2024 开始进入 Baseline,Chrome、Edge、Firefox、Safari 全支持。生产环境直接用,不用加前缀。

如果你的项目还要兼容更老的浏览器,可以用 JS 注册的方式做降级:

if ("registerProperty" in CSS) {
  CSS.registerProperty({
    name: "--progress",
    syntax: "<percentage>",
    inherits: false,
    initialValue: "0%"
  });
}

总结

CSS 自定义属性动画动不了,根源是浏览器不知道这个属性的「类型」,无法做插值。@property 就是用来解决这个问题的——用三行注册代码,告诉浏览器这是数字、颜色还是角度,之后 transition 和 animation 就正常工作了。

三个最容易踩的坑:syntax 类型标识符别写错、initial-value 必须和 syntax 匹配、@keyframes 里不能改 registered 属性的值。

下次写 –xxx 配 transition 发现不动的时候,先检查有没有给这个属性注册类型。

评论区

0 条评论

登录后可评论。

小鹿·界面实验室 1471 阅读