CSS variables have been around for a little bit now, and I have really been enjoying the new feature. At first, I thought these variables were similar to variables you’d find in SASS or LESS, more for convenience and organization than anything else. However, as I’ve experimented more with them, I’ve discovered there’s a lot more power hiding under this unassuming facade. For CSS variables follow all the rules of normal CSS styles, which means you can override variables based on specificity and media queries.

Now, we can change properties of elements without having to explicitly declare rules for each one. This opens up so many more possibilities than a precompiler can accomplish, and it does it with an ease that I can appreciate. As you can see in this demo, we can create a light/dark mode toggle using only updating variables.

See the Pen More Fun with CSS Variables by Kevin Glover (@kevinglover) on CodePen.


Here, I’m using CSS variables in the main style definitions, so I only have to update the variable values without worrying about how they are assigned. I define global variables, such as the light/dark colors, using the :root pseudo-class.

:root {
  --light-mode-bg-color: #FEFEFE;
  --light-mode-font-color: #333;
  
  --dark-mode-bg-color: #111;
  --dark-mode-font-color: #DEDEDE;
  
  --background-color-transition: background-color 0.6s ease;
  --font-color-transition: color 2s ease;
  
  --theme-transition: var(--background-color-transition), var(--font-color-transition);
}

Notice that you can use variables to define other variables, even going so far as combining multiple variables into a single variable. The ability to set the value of a variable to another variable is the secret sauce.

After defining the variables, I can use those variables when styling main like so -

main {
  background-color: var(--bg-color, white);
  color: var(--font-color, black);
}

Now that the variables are used, we can manipulate them to update the styles.

input[value='light']:checked ~ main {
  --bg-color: var(--light-mode-bg-color);
  --font-color: var(--light-mode-font-color);
}

Note that I’m not overridding background-color or color, but the variable itself. We are triggering a style update when the variable value changes, and we are updating the variable by defining it on an increased level of specificity.

We are able to write much more declarative code with CSS by stating WHAT properties should change instead of defining out all the ways in which they could change. CSS variables don’t use the cleanest syntax (with double dashes and parentheses), but they are worth the trouble.

One last thing… CSS variables even work when defining animations, so there’s even more oppertunity to clean up our stylesheets! This is especially useful when dealing with multiple elements that have similar animations such as the example below where we’re recreating the breath animation from the Apple Watch.

See the Pen Apple Watch Breathe App - using variables by Kevin Glover (@kevinglover) on CodePen.


Compare the old way where we’d have to redefine the animation each element…

/* We'll have to copy this whole thing for each :( */
.circle:nth-child(1) {
  animation: grow-circle-1 4s ease alternate infinite;
}

@keyframes grow-circle-1 {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(-35px, -50px);
  }
}
/* Hope I don't forget to create one of these or make a mistake */

…with using CSS variables.

.circle {
  animation: grow 4s ease alternate infinite;
}

/* We only have to be concerned with the variances for each element */ 
.circle:nth-child(1) {
  --growX: -35px;
  --growY: -50px;
}
/* and nothing else */

@keyframes grow {
  0% {
    transform: translate(0, 0);
  }
  100% {
    transform: translate(var(--growX), var(--growY));
  }
}

It might seem self-evident, but I’m amazed by just how much cleaner styles can be using CSS variables. It’s such a small thing that has such a large impact. You can use CSS variables in all modern browsers except IE 11 and IE Edge 15 for some reason (IE Edge 16+ works without issues though), so try it out yourself!