How to Use CSS Variables for Animation

When we mention CSS in discussions we often speak of it as a dumbed down language. A declarative language, lacking logic and insight; but that isn’t the true reality. For years developers have been craving variables in standard CSS, having been spoiled by pre-processors such as LESS and Sass for so long.

How to Use CSS Variables for Animation

Not only are CSS variables a real and tangible option for developers, they can also be used in animation scenarios. Still skeptical? Follow along to find out more!

Variable Basics

CSS variables are stored values intended for reuse throughout a stylesheet. They’re accessible using the custom var() function and set using custom property notation.

:root {
  --main-color: goldenrod;
}

div {
  background-color: var(--main-color);
}

Variables defined within :root are global, whereas variables defined within a selector are specific to that selector.

div {
  --module-color: goldenrod;
  background-color: var(--module-color);
}

In the example above any div will accept the variable, but we could get more specific with naming using targeting methods such as class and id for example.

The var() function can also accept fallback values too.

.nav {
    background: var(--navbg, blue);
}

This can be useful in situations when a variable isn’t yet defined or when working with custom elements and the Shadow DOM.

CSS variables aren’t quite ready for prime time, but the outlook for the future is very bright with many leading browsers already implementing the spec. It’s only a matter of time until they can be used without any worries, and that time is approaching fast.

Variables for Animation

There are many options for combining CSS variables with animation. Think about contexts such as audio visualizations, JavaScript event-driven scenarios, and even CSS driven events such as hover, focus and target. In theory, an Apple Watch could be connected to an API whilst using a CSS variable-based animation of a beating heart. Then we have accelerometers, device tilt APIs and even gamepad APIs, but why should we consider animating with CSS Variables at all? Here are some reasons:

  • Easily debuggable.
  • No excessive DOM manipulation.
  • DOM node independent.
  • Theming
  • Works with SVG.

Operations in CSS are really the key part to the whole puzzle with animations. CSS functions such as calc can accept a value at runtime and execute operators such as multiplication, division, addition, subtraction, mutating values into a new ones. This helps make CSS variables dynamic.

CSS Variables in JavaScript

Now that we know what CSS variables look like and what they can do it’s time to gain an understanding how JavaScript fits into all this.

document.documentElement.style.getPropertyValue('--bgcolor');
document.documentElement.style.setProperty('--bgcolor', 'red');
document.documentElement.style.removeProperty('--bgcolor');

The methods shown above are used to set, get and remove property values. They can be used for our typical CSS properties (background-color, font-size etc), but they can also be used for CSS variables too. These options will set a new value for the globally defined property otherwise known as :root in CSS.

They’re also the true secret to animating with CSS variables because our JS methods can get, set or remove a variable at run-time dynamically!

var element = document.querySelector('div');

element.style.getPropertyValue('--bgcolor');
element.style.setProperty('--bgcolor', 'red');
element.style.removeProperty('--bgcolor');

You can also set a new value for a specific element if desired. In the example snippet above we’re manipulating a variable that is attached to a div selector versus being attached globally.

Demos In the Wild

There are plenty of awesome and extremely talented developers building and experimenting with these concepts of reactive and theme-based animations using CSS variables. Here are just a few pens to dive into and discover what’s going on under the hood.

Sunset/Sunrise

By David Khourshid.

This example shows the power of CSS variable animations used in a theme-based manner. It would generally be twice as much code to execute this demo without CSS variables and many times more if you desired to exceed two themes.

CSS Variables Animation

By GRAY GHOST.

Here’s another example using mouse events in JavaScript that drive the location of a circle.

Each time you move your mouse the JavaScript updates our declared variables, allowing the circle to move position in relation to your cursor.

Alex the CSS Husky

By David Khourshid.

Here’s the same principle demonstrated above, but used in another context.

Notice what happens when you move your mouse around? Pretty cool huh?

Animation with CSS Variables

By Wes Bos.

How about updating the values of variables in other ways? Let’s take a look at the following demo by Wes Bos using sliders to update the positions of a picture.

Move the sliders around at your leisure. Notice the coolness that ensues? Simple, but simply magical and all it’s doing is updating the variables for the transform position each time the sliders are adjusted. Suuuuhhhweeet!

Single Div Accordion (Animated with CSS Variables)

By Dan Wilson.

How about something a little different for the musicians out there? Check out this hip accordion by Dan Wilson.

Whoa! Watch those keys move! This might seem a bit intimidating to go through, but at the core it’s just JavaScript updating CSS variables. Nothing more, nothing less.

CSS Variables + Transform = Individual Properties (with Inputs)

By Dan Wilson.

In this demo, use the input ranges to modify each transform property and witness how smooth they are even if you change a property mid transition.

Side Effects of CSS Variables

As CSS variables are always inheritable properties, they can cause a style recalculation of children, adversely effecting performance in the process. This will be something you have to measure, as opposed to guessing depending on your context.

Huh, it seems modifying CSS variables on an element triggers a style recalculation for _all_ of its children. Ouch. pic.twitter.com/jvpDT5UB2h

— Joni Korpi (@jonikorpi) May 18, 2017

Here’s a demo Shaw posted on the Animation at Work Slack group that was used for testing: CSS Variables Recalc Style Performance Test

During tests (Chrome 58. Mac 10.12) it was discovered that when the Set CSS Var button is triggered until the time the browser paints the background there’s 52.84ms of recalc time and 51.8ms rendering. Switching gears to the CSS Property test a very different result is discovered. From the time the Set CSS Property button is triggered until the background paints there’s roughly 0.43ms of recalc and 0.9ms rendering.

If you switch background out for color you’ll get equivalent measurements since currentColor might or might not exist in the children (shout out to David Khourshid). Any property that is inheritable will always cause a style recalc for any and all children. The property background-color is not inheritable, hence the tremendous difference with CSS variables which are always inheritable. Typically CSS properties that default to inherit will in most cases cause a large recalc of styles. It’s still important to note that changing CSS variables continually can be a performance drain. A good practice to avoid this is to animate CSS variables at the most specific level (or deepest level), in order to prevent a multitude of children affected. You can read more about reducing the scope and complexity of style calculations via Google’s Web Fundamentals page.

Conclusion

I encourage you all to dive in and test this demo for yourselves and make your own conclusion/changes/custom tests and share your results in the comments. The main takeaway in all of this is that CSS variables offer huge flexibility, but there will be performance implications for setting CSS variables on a parent with a vast amount children.

Special thanks to the gang in the Animations At Work Slack channel for the ongoing testing, feedback and discussions (David Khourshid, Joni Korpi, Dan Wilson and Shaw).

Resources