CSS Custom Properties: Variables

Variables invariably exist in all programming languages, and that's because they are pretty useful. You just have to store a value in a variable once, and then you can use it later multiple times, avoiding repetition. While CSS is not a programming language, lack of variables still limits its capabilities.

Now that the native CSS variables are around, I would like to discuss how they are different from variables that CSS preprocessors provide and how to use them properly.

Advantages of Custom Properties

The syntax for using custom properties is a bit verbose, and some developers might consider it ugly. One more factor that discourages the use of native variables is the existing support provided by Sass variables.

While preprocessors like Sass support variables, they still have some limitations that I will discuss in this section.

You can't update preprocessor variables based on media queries. To make a site responsive, you need to change values based on screen dimensions. Preprocessor variables can't do that. For instance, consider the following code:

As you can see, the assignment inside the media query is completely ignored. On the other hand, CSS variables will respect this assignment inside a media query.

Similarly, preprocessor variables neither cascade nor inherit. Using native variables, you can do away with all these limitations. One more important advantage of using native variables is that they are interoperable. Unlike Sass variables, which will work just with Sass, native variables will work not only with all preprocessors but also in plain CSS files.

Syntax and Usage

To understand how to use CSS custom properties, let's begin with a basic example:

Whenever you define a custom property, you begin by defining its scope. The scope determines the DOM nodes to which the custom property might be available. Using :root implies that the custom property is available to all elements. Keep in mind that all custom properties have to begin with two dashes.

If you intend to use a custom property, you will have to reference it with the var() function. This function takes two arguments; the first one is the custom property itself, and the second is a fallback value. The fallback value is used when a custom property is not declared on any of the ancestors or if its value is invalid.

You should note that custom properties are case sensitive. This implies that --text-color , --Text-Color, and --text-Color are all different.

There are a couple more things that should be kept in mind while using var().

The first is that the fallback values can be comma separated, and in the case of shorthand values like margin, you don't have to separate individual values with a comma. For example, var(--para-font-family, "Lato", "Roboto"); sets the fallback value as "Lato" "Roboto";. Similarly, a fallback for border property will look like:

a {
border : var(--link-border, 1px dotted brown);
}

The second is that you cannot use variables as property names. The following code will throw an error on the second declaration.

h1 {
--my-size: font-size;
var(--my-size): 2em;
}

Setting Values With Calc()

With the basics covered, let's see how we can build up values from custom properties. If you have assigned a bare number to a variable, you won't be able to append it directly to some unit to get a valid value. In short, the code below is invalid:

The above statement is completely valid and sets the value of --h-color equal to --p-color.

Changing Themes Dynamically

Variables can provide a lot of flexibility when it comes to changing themes based on a user's preferences. Earlier, you had to either use inline styling or create multiple stylesheets. Both these methods have their own demerits. Creating multiple stylesheets is a headache, and using inline styling is bad practice. Variables can provide an easy way out in this situation. Here is some basic JavaScript to change themes dynamically:

The code above attaches a click event to our theme button. As soon as someone clicks on it, the function greenTheme() sets the values of a few variables to change the overall look of the website. As you can see, this method was much easier to implement than the other two solutions.

Final Thoughts

The tutorial might seem to suggest that native CSS variables are superior to variables in preprocessors like Sass, but I am in no way undermining the usefulness of preprocessors. Using various CSS preprocessors increases productivity. They have much more to offer than just variables. Numerous built-in functions, loops, and conditional statements can get things done quickly.

This tutorial merely points out that even if native variables have a weird syntax, they still have a lot more to offer and are worth using in your projects. If you have any questions regarding this tutorial, let me know in the comments.