为什么我不能为自定义属性(又名 CSS 变量)设置动画?

yun*_*zen 12 css css-transitions css-animations css-variables

看这个动画:

  • 金色 div 有一个动画,其中自定义属性被动画化
    @keyframes roll-o-1animates --o)。
    这一步动画。
  • 银色 div 有一个动画,其中一个普通属性被动画化
    @keyframes roll-o-2animates left)。
    这会连续动画。

为什么金色 div 动画不流畅?
是否有任何解决方法也使用变量?

#one {
  width: 50px;
  height: 50px;
  background-color: gold;
  --o: 0;
  animation: roll-o-1 2s infinite alternate ease-in-out both;
  position: relative;
  left: calc(var(--o) * 1px);
}

@keyframes roll-o-1 {
  0% {
    --o: 0;
  }
  50% {
    --o: 50;
  }
  100% {
    --o: 100;
  }
}

#two {
  width: 50px;
  height: 50px;
  background-color: silver;
  --o: 0;
  animation: roll-o-2 2s infinite alternate ease-in-out both;
  position: relative;
}

@keyframes roll-o-2 {
  0% {
    left: 0px;
  }
  50% {
    left: 50px;
  }
  100% {
    left: 100px;
  }
}
Run Code Online (Sandbox Code Playgroud)
<div id="one"></div>
<br>
<div id="two"></div>
Run Code Online (Sandbox Code Playgroud)

Dan*_*eld 10

当被问到这个问题时,无法为自定义属性设置动画,正如@temani afif 正确指出的那样 -

因为 UA 无法解释其内容

从那时起,CSS Houdini整合了CSS 属性和值 API 规范

该规范扩展了 [css-variables],允许通过两种方法注册具有值类型、初始值和定义的继承行为的属性:

一个 JS API, registerProperty() 方法

一个 CSS 规则,@property 规则

所以现在您可以注册自己的自定义属性 - 包括自定义属性的类型 - 动画自定义属性变得可能。

通过 CSS 注册自定义属性 - 使用@property规则

@property --o {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
Run Code Online (Sandbox Code Playgroud)

@property --o {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
Run Code Online (Sandbox Code Playgroud)
#one {
  width: 50px;
  height: 50px;
  background-color: gold;
  --o: 0;
  animation: roll-o-1 2s infinite alternate ease-in-out both;
  position: relative;
  left: calc(var(--o) * 1px);
}

@keyframes roll-o-1 {
  0% {
    --o: 0;
  }
  50% {
    --o: 50;
  }
  100% {
    --o: 100;
  }
}

#two {
  width: 50px;
  height: 50px;
  background-color: silver;
  animation: roll-o-2 2s infinite alternate ease-in-out both;
  position: relative;
}

@keyframes roll-o-2 {
  0% {
    left: 0px;
  }
  50% {
    left: 50px;
  }
  100% {
    left: 100px;
  }
}

@property --o {
  syntax: "<number>";
  inherits: false;
  initial-value: 0;
}
Run Code Online (Sandbox Code Playgroud)

要通过 javascript 注册属性 - 使用以下CSS.registerProperty()方法:

CSS.registerProperty({
      name: "--o",
      syntax: "<number>",
      initialValue: 0,
      inherits: "false"
   });
Run Code Online (Sandbox Code Playgroud)

<div id="one"></div>
<br>
<div id="two"></div>
Run Code Online (Sandbox Code Playgroud)
CSS.registerProperty({
      name: "--o",
      syntax: "<number>",
      initialValue: 0,
      inherits: "false"
   });
Run Code Online (Sandbox Code Playgroud)
CSS.registerProperty({
  name: "--o",
  syntax: "<number>",
  initialValue: 0,
  inherits: "false"
});
Run Code Online (Sandbox Code Playgroud)

NB

浏览器支持目前仅限于 chrome(v78+ for registerProperty(),v85+ for @property)edge 和 opera


Tem*_*fif 9

规范

动画:否

然后

值得注意的是,它们甚至可以被转换或动画,但由于 UA 无法解释它们的内容,它们总是使用“50% 翻转”行为,该行为用于任何其他无法智能插值的值对。但是,@keyframes 规则中使用的任何自定义属性都会被动画污染,这会影响通过动画属性中的 var() 函数引用时的处理方式。

所以基本上,您可以在属性上使用过渡和动画,其中它们的值是使用自定义属性定义的,但您不能为自定义属性执行此操作。

请注意以下示例中的不同之处,其中我们可能认为两个动画相同但不相同。浏览器知道如何动画,left但不知道如何动画使用的自定义属性left(也可以在任何地方使用)

#one {
  width: 50px;
  height: 50px;
  background-color: gold;
  animation: roll-o-1 2s infinite alternate ease-in-out both;
  position: relative;
  left: calc(var(--o) * 1px);
}

@keyframes roll-o-1 {
  0% {
    --o: 0;
  }
  50% {
    --o: 50;
  }
  100% {
    --o: 100;
  }
}

#two {
  width: 50px;
  height: 50px;
  background-color: silver;
  --o: 1;
  animation: roll-o-2 2s infinite alternate ease-in-out both;
  position: relative;
}

@keyframes roll-o-2 {
  0% {
    left: calc(var(--o) * 1px);
  }
  50% {
    left: calc(var(--o) * 50px);
  }
  100% {
    left: calc(var(--o) * 100px);
  }
}
Run Code Online (Sandbox Code Playgroud)
<div id="one"></div>
<br>
<div id="two"></div>
Run Code Online (Sandbox Code Playgroud)

另一个使用过渡的例子:

.box {
  --c:red;
  background:var(--c);
  height:200px;
  transition:1s;
}
.box:hover {
  --c:blue;
}
Run Code Online (Sandbox Code Playgroud)
<div class="box"></div>
Run Code Online (Sandbox Code Playgroud)

我们有一个过渡,但不是用于自定义属性。它用于背景,因为在:hover状态中我们再次评估值,因此背景会改变并且过渡会发生。


对于动画,即使你left在关键帧内定义了属性,你也不会有动画:

#one {
  width: 50px;
  height: 50px;
  background-color: gold;
  animation: roll-o-1 2s infinite alternate ease-in-out both;
  position: relative;
  left: calc(var(--o) * 1px);
}

@keyframes roll-o-1 {
  0% {
    --o: 0;
     left: calc(var(--o) * 1px);
  }
  50% {
    --o: 50;
     left: calc(var(--o) * 1px);
  }
  100% {
    --o: 100;
    left: calc(var(--o) * 1px);
  }
}

#two {
  width: 50px;
  height: 50px;
  background-color: silver;
  --o: 1;
  animation: roll-o-2 2s infinite alternate ease-in-out both;
  position: relative;
}

@keyframes roll-o-2 {
  0% {
    left: calc(var(--o) * 1px);
  }
  50% {
    left: calc(var(--o) * 50px);
  }
  100% {
    left: calc(var(--o) * 100px);
  }
}
Run Code Online (Sandbox Code Playgroud)
<div id="one"></div>
<br>
<div id="two"></div>
Run Code Online (Sandbox Code Playgroud)

  • 需要明确的是:在您的过渡示例中,您应该区分`transition: background 1s;`(工作)和`transition: --c 1s;`(不工作)。 (2认同)

yun*_*zen 5

我可以使用新的CSS Properties and Values API Level 1
(CSS Houdini 的一部分;W3C 工作草案,截至 2020 年 10 月 13 日)来做到这一点

我只需要使用@property规则注册我的自定义属性

    @property --o {
      syntax: "<number>";
      inherits: true;
      initial-value: 0;
    }
Run Code Online (Sandbox Code Playgroud)

通过该syntax属性,我将此自定义属性声明为 类型 <number>这暗示浏览器应以哪种方式进行该属性的转换或动画计算。

此处syntax列出了该属性支持的值

“<长度>”
“<百分比>”
“<长度百分比>”
“<颜色>”
“<图像>”
“<url>”
“<整数>”
“<角度>”
“<时间>”
“<分辨率>"
"<变换函数>"
"<自定义标识>"

浏览器兼容性非常强,因为这是一个实验性功能并且处于草案状态(另请参阅caniuse)。Chrome 和 Edge 支持它,Firefox 和 Safari 不支持。

<edit> Safari 从 16.4 开始支持它。Firefox 将在版本 118 中支持它,这是当前的夜间版本,将于 2023 年 9 月下旬发布:</edit>

<edit> Firefox 118 的发布似乎被推迟了。按照现在的计划,它将与版本 120 一起发布,即当前的 Nightly,于 2023 年 11 月 21 日发布。唉,我无法确认这在 Nightly 中是否有效。

    @property --o {
      syntax: "<number>";
      inherits: true;
      initial-value: 0;
    }
Run Code Online (Sandbox Code Playgroud)
@property --o {
  syntax: "<number>";
  inherits: true;
  initial-value: 0;
}

#one {
  width: 50px;
  height: 50px;
  background-color: gold;
  --o: 0;
  animation: roll-o-1 2s infinite alternate ease-in-out both;
  position: relative;
  left: calc(var(--o) * 1px);
}

@keyframes roll-o-1 {
  0% {
    --o: 0;
  }
  50% {
    --o: 50;
  }
  100% {
    --o: 100;
  }
}

#two {
  width: 50px;
  height: 50px;
  background-color: silver;
  --o: 0;
  animation: roll-o-2 2s infinite alternate ease-in-out both;
  position: relative;
}

@keyframes roll-o-2 {
  0% {
    left: 0px;
  }
  50% {
    left: 50px;
  }
  100% {
    left: 100px;
  }
}
Run Code Online (Sandbox Code Playgroud)