Why can’t I animate custom properties (aka CSS variables)?

When this question was asked, it wasn’t possible to animate custom properties, as @temani afif correctly pointed out –

since the UA has no way to interpret their contents

Since then, CSS Houdini have put together the CSS Properties and Values API specification

This specification extends [css-variables], allowing the registration
of properties that have a value type, an initial value, and a defined
inheritance behaviour, via two methods:

A JS API, the registerProperty() method

A CSS at-rule, the @property rule

So now that you can register your own custom properties – including the type of the custom property – animating the custom property becomes possible.

To register the custom property via CSS – use the @property rule

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

To register the property via javascript – use the CSS.registerProperty() method:

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 is currently limited to chrome (v78+ for registerProperty(), v85+ for @property) edge and opera

Leave a Comment