Using CSS Custom Properties with SASS/LESS variables.

Using CSS Custom Properties with SASSLESS variables
Reading Time: 6 minutes

A question that was raised in a facebook group, CSS Masters Israel, about letting your customer to control colors on their site, got me thinking about how we can allow this in the easiest way for everyone: developers, and the customers, while maintaining a template approach so you can use the same site build for multiple customers. Preprocessor variables and CSS Custom Properties are the first things that came to mind.



What do You need to know?

Well, not a lot. You’d need to know how to use CSS preprocessors (like LESS/SASS) or Postprocessors (like POSTCSS).

I will be using SASS for my demos, but in this case, SASS and LESS are pretty similar. I will of course, point out the differences, if they happen to matter.


Meet the Players!

LESS/SASS variables

Preprocessor variables are a great way to maintain things on your site, you can define variables for pretty much anything, but we will only use them as values for now.

Declaring a LESS/SASS variable is simple:

$var-name: green;

BODY {
    color: $var-name;
}

Note: in LESS variable names start with @ and not $.

This will compile to:

BODY {
    color: green;
}

There is alot more you can do with LESS/SASS variables, but those things are less relevant to the problem at hand.

CSS Custom Properties

CSS Custom properties, referred to some as “CSS Variables”, are a relatively new feature, that allows you to change properties in your CSS dynamically. It’s the best way to allow theming, dynamic changes to anything that works as a value in your CSS.

How do they work?

Pretty simple. Declaration is pretty similar to LESS/SASS, only CSS hirarchy matters.
The basic declaration looks like this:

:root {  /* The root selector is the highest in the DOM hirarchy */
    --my-color: green;
}

After they are declared, they are called like this:

BODY {
    color: var(--my-color);
}

Custom property name will always begin with --. And it can be used as any value in your code, here is a quick demo. Play with the custom properties in the beginning of the code to see them at work:

See the Pen CSS Custom Properties Basic demo by Lurx (@lurx) on CodePen.

As you can see in the demo above, you can use Custom Properties as part of a value and in shorthands as specific values.

You can’t, however, use Custom properties as CSS PROPERTIES (you can’t dynamically change “color” to “background-color”, and you can’t string them together, so for example



will not work.
Also, you can’t use custom properties as SELECTORS or as part of a media query, so @media screen and (min-width: var(--min-width)) will not work, since breakpoints can’t change dynamically.

CSS Custom properties are NOT supported in Internet Explorer See: caniuse.com.

You might need to support IE, and that is fine. By the end we will have fallbacks for everything.

But what happens if we make a mistake, or call a custom property that wasn’t declared correctly (or at all)?
In that case, we can add a fallback color for just these cases. it looks like this:

BODY {
    color: var(--my-color, black);
}

In this case, if --my-color is not declared – for any reason – the color used will be black.

Let’s get to work!

Basic Setup

Our goal is to output the same box as the demo I showed before. this will be our basic CSS:

.box {
    color: blue;
    background-color: gold;
    padding: 10px;
    border: 1px solid blue;
}

This is not dynamic at all. In order for our customer to be able to change this, we need to either create a new CSS for every change, or add a CSS file (or <style> tag) for overwriting the colors.

Let’s start to make this easier to change, shall we?

While this demo only has one selector, your code will have more. Changing colors can be a pain if you have to go over hunderds/thousands of lines of code and change colors.
That’s where our preprocessor variables come in.

We’ll start add in some SASS properties:
in our _vars partial:

$box-color: blue;
$box-bg-color: gold;
$box-padding: 10px;
$box-border-color: $box-color;

And in our SCSS file:

.box {
    color: $box-color;
    background-color: $box-bg-color;
    padding: $box-padding;
    border: 1px solid $box-border-color;
}

This will compile to the same code we’ve seen before, and allow us to create more dynamic CSS files when we compile a new CSS.

Now your customer can change colors via his control panel, and your server can just edit the partial with the new values, and have a new CSS compiled.



NOTE: with LESS you have an option to use less.js in the browser, and compile a new CSS with every refresh. It is not recommended for huge sites, but if your client has a small site, it could be useful.


Make it TRUELY dynamic!

In order to make this truely dynamic site, we’ll use CSS Custom Properties. Let’s add them into our code.

/* SASS VARIABLES */
$box-color: blue;
$box-bg-color: gold;
$box-padding: 10px;
$box-border-color: $box-color;

/* CSS Custom Properties */
:root {
    --my-box-color: #{$box-color}; /* set the value with the SASS vars (with interpolation) */
    --my-bg-color: #{$box-bg-color};
    --my-padding: #{$box-padding};
    --my-border-color: #{$box-border-color};
}

And in our SCSS file:

.box {
    color: var(--my-box-color);
    background-color: var(--my-bg-color);
    padding: var(--my-padding);
    border: 1px solid var(--my-border-color);
}

**NOTE: This is using Interpolation, if you’re note sure what this is, you’ll have to read about that later.

Like you’ve seen earlier, this will make the properties in .box dynamic and changable on the fly.

Adding feature support with @supports

Obviously, not all browsers support CSS Custom Properties. But that doesn’t mean we shouldn’t let those browsers who do have a little fun with them.

@supports is a feature query. It allows you to specify declarations that depend on a browser’s support for one or more specific CSS features. In this example, <body> is set to display: block, but if the browser supports using display: grid, it will be overwritten. If not – the browser will ignore the entire set of rules inside the @supports query.

BODY {
    display: block;
}

@supports(display: grid) {
    BODY {
        display: grid;
    }
}

To check if the user’s browser supports CSS Custom Properties, we’ll just specify @supports(--my-var: green). So for our demo, we’ll use the both pieces of code we’ve seen earlier:

/* SASS VARIABLES */
$box-color: blue;
$box-bg-color: gold;
$box-padding: 10px;
$box-border-color: $box-color;

/* CSS Custom Properties */
:root {
  --my-box-color: #{$box-color}; /* we&#039;re setting the value with the SASS variable */
    --my-bg-color: #{$box-bg-color};
    --my-padding: #{$box-padding};
    --my-border-color: #{$box-border-color};
}

/* Basic setup for defaults */
.box {
    color: $box-color;
    background-color: $box-bg-color;
    padding: $box-padding;
    border: 1px solid $box-border-color;
}

/* Check for Custom Properties support, and apply them */
@supports(--my-box-color: $box-color) {
    .box {
            color: var(--my-box-color, $box-color);
            background-color: var(--my-bg-color, $box-bg-color);
            padding: var(--my-padding, $box-padding);
            border: 1px solid var(--my-border-color, $box-border-color);
    }
}

Now, changing the values can be really easy with a single class, in a <style> tag (and of course, or inline style. Adding this new class to <div class="box"> will simply change the values of the custom properties, and will change on the fly in the browser (if supported, of course):

.newclass {
    --my-box-color: green;
    --my-bg-color: pink;
    --my-padding: 1rem;
    --my-border-color: var(--my-box-color);
}

This solution will not only allow your customer to control colors (or anything you choose he should be able to), it will also allow you to create a live demo for these things without compilation, in the supported browsers.


Read more about CSS Custom Properties and Preprocessor variables:


I hope you enjoyed reading this post, and have learned something new from it. Let me know in the comments what you think.