为什么我不能为自定义属性设置动画?

时间:2019-02-08 14:08:52

标签: css css3 css-transitions css-animations css-variables

观看此动画:

  • 金色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>

4 个答案:

答案 0 :(得分:6)

提出此问题时,无法动画自定义属性,正如@temani afif正确指出的那样-

因为UA无法解释其内容

从那时起,CSS Houdini汇集了CSS Properties and Values API specification

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

JS API,registerProperty()方法

CSS规则@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>

NB

Browser support当前仅适用于Chrome浏览器(对于registerProperty()为v78 +,对于@property为v85 +)边缘和歌剧

答案 1 :(得分:3)

并非所有CSS属性都是​​可动画的,因此您无法为css变量设置动画。这是可以为https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_animated_properties设置动画的属性的列表

答案 2 :(得分:2)

来自the specification

  

可设置动画:否

然后

  

值得注意的是,它们甚至可以进行过渡或动画化,但是由于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>

答案 3 :(得分:2)

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

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

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

通过 syntax 属性,我将此自定义属性声明为 type <number>,这会提示浏览器应该以何种方式来计算此属性的转换或动画发生。

列出了 syntax 属性支持的值here

Browser compatibility 非常强大,因为这是一项实验性功能并且处于草稿状态(另请参阅 caniuse)。 Chrome 和 Edge 支持,Firefox 和 Safari 不支持。

@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>