Home

Time Uniform For CSS Animation

29 January 2021

I noticed that in common shader programs, animation is based on the time uniform value. Other values which are going to animate will be calculated according to it and keep updating as time changes. So there's animation.

That's quite different from keyframe based animation in CSS. As someone who has used CSS for animation for years, it feels very novel to me since it requires a kind of different thinking model.

Here's my experiment of adding time uniform to CSS.

Pure CSS solution

You may think of using requestAnimationFrame() dynamically update the time variable and pass it to CSS via custom property. But there's another interesting way in pure CSS.

The @property API of CSS Houdini makes it possible to animate a number. First we need to regsiter a variable, such as --t for example.

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

Why don't use <Integer> here? Because its maximum length is 6 digits, after 999999 it becomes 0 and sticks to it.

The next step is to increase the value of variable --t using animation. The animation needs to be running as long as possible in order to simulate the never-ending time ticks. Nobody will likely to run the animation for a year so it's fairly safe to set the animation duration to be a year. That's 31536000000 in ms.

@keyframes animate-time {
  from { --t: 0 }
  to   { --t: 31536000000 }
}
/* Put animation to :root so we can use --t everywhere */
:root {
  animation: animate-time 31536000000ms linear infinite;
}

The variable --t will increase by 1000 linearly in one second. It's enough to make the transitions smooth.

Usage

Here is how to animate an element without writing keyframes. Pretty simple, huh?

element {
  transform: rotate(var(--t) * .2deg);
}

If you want to rotate the element by 1turn in 10s, calculate it manually.

element {
  transform: rotate(
    calc(var(--t) / 1000 / 10 * 1turn)
  );
}

Colors can be animated by changing hue in hsl().

element {
  background: hsl(
    calc(var(--t) * .072), 60%, 60%
  );
}

Limitations

The operations of CSS calc() function is quite limited support. There isn't any way to do modulo calculation, which is quite useful, since the value of --t changes in one direction.

There also lacks the periodic functions like cos() and sin(). I've been waiting for too long since I first heard the news below.

Currently the time uniform is OK for simple rotation and color animations. Hope browsers support native Math functions in CSS soon.

Add to css-doodle

In the latest css-doodle version, you can access the time uniform through @t function. The @property syntax is not supported inside web components so I registered it using CSS.registerProperty().

It may not be quite useful at the moment, but I'm sure it's something for the future.

@grid: 1 / 140px;
clip-path: @shape(
  split: 120;
  frame: 15;
  r: cos(t/10)^sin(t)^sin(2t)*.9;
);
transform: rotate(calc(@t * .0001turn));
background: linear-gradient(
  @m3(hsl(calc(@t/@r(15, 20)), 60%, 60%))
);
@grid: 1 / 120px; clip-path: @shape( split: 120; frame: 15; r: cos(t/10) ^ sin(t) ^ sin(2t) * .9; ); background: linear-gradient( @m3(hsl(calc(@t/@r(15, 20)), 60%, 60%)) ); transform: scale(1.2) rotate(calc(@t * .0001turn));

Links to demos

Google Chrome is required to view animations in this article at the time of writing.