<< ../posts/Sailing the glass sea Back to index... ../posts/A fun experiment with grid representation. >>

Minor Gripe

2020-12-28 -- 1 Weird CSS Trick

Chris Ertel

Introduction

Before we get into anything else, please behold this gross hack:

<html>
  <head></head>
  <style>
    @keyframes spin {
      from { transform: rotate(0deg); }
      to { transform: rotate(360deg); }
    }

    .spinny {
      width: 100px;
      height: 100px;
      animation-name: spin;
      animation-duration: var(--theta);
      animation-iteration-count: infinite;
      animation-timing-function: linear;
    }
  </style>
  <body>
    <h1>Animation demo</h1>
    <div style="" class="spinny">:(</div>
    <div style="--theta: 4000ms" class="spinny">:)</div>
    <div style="--theta: 2000ms" class="spinny">:D</div>
    <div style="--theta: 500ms" class="spinny">XD</div>
  </body>
</html>

Please load this into a file and view it on your local machine.

What’s going on here?

We create an animation class (spinny) using a relatively boring animation (spin). We then create four divs showing varying degrees of rotation.

The interesting part is the use of CSS custom properties. The –theta property is used via var(–theta) in the spinny class definition; whenever that class is used, it’s going to attempt to spin the element. However, the speed of the animation is going to be based on the animation-duration property, which is not defined for the first element. But, if you look at the other three divs, you see a style attribute being set which binds that custom property to a particular–and more importantly element-specific–value, and so the animation speed for each element is different.

For what purpose?

I’ve been doing some…weird…things with Phoenix LiveView recently. I’m not ready to talk about it yet much. However, the salient point is that LiveView will patch DOM elements and properties at the behest of the server.

So, imagine if you have a bunch of elements that you want to animate but you don’t want the server to have to do everything. Say, for example, you have a sprite that needs to move across the screen.

Well, the server can of course push down new positions for every step of the way. That’s great, but means the poor server has to do a lot of work to keep up with many clients at 60fps. And for the end user, if the latency gets too high or the server takes too long between updates, it looks like the div is teleporting across its path.

What if instead, we had a CSS animation that offset the sprite in the direction of travel? That would animate at 60fps and do all of the work client-side. Because animations are reset every time the element is touched (due to something about how LiveView does DOM patching, though of course other methods exist) if a server update comes through mid-animation with a new position that’s fine–we’re using a linear interpolation anyways, so restarting the same animation from a new position on the same trajectory won’t matter. When the server update comes to say “hey, we’re no longer moving”, the class just needs to be left off in the update.

Pretty neat–or as a colleague put it:

haha holy shit that’s the product of a deranged mind, and I’m all for it


<< ../posts/Sailing the glass sea Back to index... ../posts/A fun experiment with grid representation. >>