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

问题描述 投票:0回答:5

看这个动画:

  • 金色 div 有一个自定义属性动画的动画
    @keyframes roll-o-1
    动画
    --o
    )。
    这是分步动画的。
  • 银色 div 有一个动画,其中 normal 属性是动画的
    @keyframes roll-o-2
    动画
    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;
  }
}
<div id="one"></div>
<br>
<div id="two"></div>

css css-transitions css-animations css-variables
5个回答
19
投票

当提出这个问题时,无法对自定义属性进行动画处理,正如 @temani afif 正确指出的那样 -

因为UA无法解释其内容

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

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

一个 JS API,registerProperty() 方法

CSS at 规则,@property 规则

现在您可以注册自己的自定义属性 - 包括自定义属性的类型 - 为自定义属性设置动画成为可能。

要通过 CSS 注册自定义属性 - 使用

@property
规则

@property --o {
  syntax: "<number>";
  inherits: false;
  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;
  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;
}
<div id="one"></div>
<br>
<div id="two"></div>

要通过 javascript 注册属性 - 使用

CSS.registerProperty()
方法:

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

CSS.registerProperty({
  name: "--o",
  syntax: "<number>",
  initialValue: 0,
  inherits: "false"
});
#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;
  }
}
<div id="one"></div>
<br>
<div id="two"></div>

注意

浏览器支持目前仅限于chrome(

registerProperty()
为v78+,
@property
为v85+)edge和opera


11
投票

来自规格

可动画:否

然后

值得注意的是,它们甚至可以进行过渡或动画,但是由于 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);
  }
}
<div id="one"></div>
<br>
<div id="two"></div>

另一个使用转换的例子:

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

我们有一个过渡,但不是针对自定义属性的。这是用于背景的,因为在

: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);
  }
}
<div id="one"></div>
<br>
<div id="two"></div>


4
投票

并非所有 CSS 属性都是可动画的,并且您无法对 CSS 变量进行动画处理。这是您可以设置动画的属性列表https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties


4
投票

我可以使用新的 CSS 属性和值 API 级别 1
来做到这一点 (CSS Houdini 的一部分;W3C 工作草案,截至 2020 年 10 月 13 日)

我只需要使用

@property
规则来注册我的自定义属性

    @property --o {
      syntax: "<number>";
      inherits: true;
      initial-value: 0;
    }

通过

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

此处

列出了 syntax 属性支持的值









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

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

Firefox 118 的发布似乎被推迟了。按照现在的计划,它将与版本 120 一起发布,发布时间为 2023 年 11 月 21 日

@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; } }
<div id="one"></div>
<br>
<div id="two"></div>


0
投票
也许不是您正在寻找的答案,但我使用 javascript 动画(fx with gsap)实现了这一点

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> <style> body,html { height: 100%; display: flex; } .wrapper { margin: auto 0; } .box { --animate:0; background-color: tomato; height: 70px; width: 70px; transform: translateX(calc(var(--animate) * 1px)) rotate(calc(var(--animate) * 1deg)); } </style> </head> <body> <div class="wrapper"> <div class="box"></div> <button onclick="play()">Play</button> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/gsap/3.9.1/gsap.min.js" integrity="sha512-H6cPm97FAsgIKmlBA4s774vqoN24V5gSQL4yBTDOY2su2DeXZVhQPxFK4P6GPdnZqM9fg1G3cMv5wD7e6cFLZQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script> <script> const tween = gsap.to(".box",{ "--animate":900, duration:10 }) tween.pause(); function play() { tween.progress(0); tween.play(); } </script> </body> </html>

© www.soinside.com 2019 - 2024. All rights reserved.