DEV Community 👩‍💻👨‍💻

Cover image for Dynamic animations with CSS variables
Top
Top

Posted on

Dynamic animations with CSS variables

Keyframe animations are cool enough on their own, but when we mix them with CSS variables (AKA CSS custom properties), things get ⚡️ next-level ⚡️.

<style>
  @keyframes bounce {
    from {
      transform: translateY(0px);
    }
    to {
      transform: translateY(-20px);
    }
  }

  .box {
    animation:
      bounce 300ms
      alternate infinite
      cubic-bezier(.2, .65, .6, 1);
  }
</style>

<div class="box"></div>
Enter fullscreen mode Exit fullscreen mode

CSS animations are meant to be generic and reusable, but this animation will always cause an element to bounce by 20px. Wouldn't it be neat if different elements could supply different "bounce heights"?

With CSS variables, we can do exactly that:

<style>
  @keyframes bounce {
    from {
      transform: translateY(0px);
    }
    to {
      transform: translateY(
        var(--bounce-offset)
      );
    }
  }

  .box {
    animation:
      bounce alternate infinite
      cubic-bezier(.2, .65, .6, 1);
  }
  .box.one {
    --bounce-offset: -20px;
    animation-duration: 200ms;
  }
  .box.two {
    --bounce-offset: -30px;
    animation-duration: 300ms;
  }
  .box.three {
    --bounce-offset: -40px;
    animation-duration: 400ms;
  }
</style>

<section>
  <div class="box one"></div>
  <div class="box two"></div>
  <div class="box three"></div>
</section>
Enter fullscreen mode Exit fullscreen mode

Our @keyframes animation has been updated so that instead of bouncing to -20px, it accesses the value of the --bounce-offset property. And since that property has a different value in each box, they each bounce to different amounts.

This strategy allows us to create reusable, customizable keyframe animations. Think of it like props to a React component!

Derived values with calc
So, something bothers me about the example above.
With the translateY function, positive values move the element down, negative values move the element up. We want to move the element up, so we have to use a negative value.

But this is an implementation detail. When I want to apply this animation, it's weird that I need to use a negative value.

CSS variables work best when they're semantic. Instead of setting --bounce-offset to a negative value, I'd much rather do this:

.box.one {
  --bounce-height: 20px;
}

Using calc, we can derive the true value from the provided value, within our @keyframes at-rule:

@keyframes bounce {
  from {
    transform: translateY(0px);
  }
  to {
    transform: translateY(
      calc(var(--bounce-height) * -1)
    );
  }
}

We only define this keyframe animation once, but we'll likely use it many times. It's worth optimizing for the "consumer" side of things, to make it as pleasant to use as possible, even if it complicates the definition a bit.
calc lets us craft the perfect APIs for our keyframe animations. 💯

Top comments (0)

👀 Just want to lurk?

You can still create an account and turn on features like 🌚 dark mode.