CSS Custom Properties

Maria Cristina Di Termine
09-05-2017

Now a day CSS processors such as SASS and LESS are normally used for all the project in web development. These CSS processors give a lot of advantages to develop quickly a great maintainable code that can be easily modified, improved and implemented.
The possibility to create variables is one of the most useful functionality that these processors provide and only this feature already simplifies readability, development and refactoring.
CSS processors’s variables have also some negative points:

  • They don’t know the structure of the DOME
  • It’s not possible to change them dynamically
  • JavaScript can’t have access to them directly

To solve some of these problems we could use CSS custom properties. They look and work as CSS variables and now all the major browsers are ready to support them. For browsers that can’t not yet support them (IE and Edge) there are already some solutions like for example consider to switch CSS, using @supports condition or using variables in parallel.

Syntax

As SASS and LESS have their own syntax to declare a variable (using $ for SASS and @ for LESS), custom properties have their own syntax too which is very simple: --
So if we want to declare a simple variable we might write something like this:

--text-color: #7930c1;
--text-padding: 0 10px;
--size: 20px;

The value of the property can be any valid CSS value (color, string, expression) and as in plain CSS, custom properties are dynamic at the same way and can be changed at any moment.
To implement the variables we need to use var(), like this:

.container {
  --text-color: #7930c1;
  --text-padding: 0 10px;
}

.container p {
color: var(--text-color);
padding: var(--text-padding);
}

If a variable is not provided, var() function can provide a default value, when we are not sure that a variable has been defined but we still want to provide a value to be used in that case:

padding: var(--text-padding, 5px);
padding: var(--text-padding, var(--box-padding));

Also calc() function is supported and we can able to use basic operations like for example:

.box {
--size: 20px;

--box-size: calc(var(--size) / 2);
}

Scoping

We know already that a closure in JavaScript is a function that can access to variables form outside. Sometimes it’s called “the scope chain” and it has 3 different levels:

  • its own scope (closure variables)
  • the outer function’s variables (enclosing variables)
  • the global variables

In CSS processors it works very similar. In SASS for example we have local and global variables and their scope depend on the code’s structure (where we define them).
CSS properties are inherited by default and they cascade. Plus, you can’t have global variables defined outside of a selector because that’s not valid CSS.
These global variables are indeed defined in the :root scope which is a selector that allows us to target the highest-level “parent” element in the DOM (like html is for HTML).
So, we could have something like this:

<!-- Here we have global scope -->
<div class="enclosing">
   <p>Here we have our enclosing</p>
   <div class="closure">
      Here we get the closure
   </div>
</div>
:root {
--myGlobalVar: 5px;
}

.enclosing {
--myEnclosingVar: 15px;
}

.enclosing .closure {
--myClosureVar: 50px;

font-size: calc(var(--closureVar) + var(--enclosingVar) + var(--globalVar));
/* From here we can access all the scopes */
}

Changes are immediately detected

If in SASS we change the value of a variable just after its usage, the change won’t have effect. Example:

.closure {
$closureVar: #ccc; // local variable used
color: $closureVar;
// #ccc is used

$closureVar: #fff; // local variable not used
}

In CSS the value changes because the color is reassigned from changed --closureVar:

.closure {
--closureVar: #ccc; // local variable not used
color: var(--closureVar);
// #ccc is used

--closureVar: #fff; // local variable used
}

Beware the DOM

Now let’s imagine we want to apply a font color elements but not if the class “special” class is present. So we have this structure:

<div class="default">
  default
</div>
<p><br /></p>
<div class="default special">
  default special
</div>

In CSS we could do it like this:

.special {
--special-color: pink;
}

.default {
--default-color: blue;

color: var(--special-color, var(--default-color));
/* Use default-color, except when special-color is provided. */
}

Now the second html element will get pink text because –special-color is used on top of --default-color, which indeed is used only if --special-color is not provided. Since we provide --special-color only in the .special class, only the element with that class will get pink text.
SASS calculations and processing happen at compilation time, and of course, it doesn’t know anything about the DOM’s structure. CSS custom properties instead are aware of the DOM’s structure and are dynamic.

Connecting with JavaScript

Using CSS custom properties we can easily communicate with JavaScript using for example the simple JS methods getPropertyValue() and setProperty() which are already used for common CSS.
Let’s imagine to have this media-query:

.breakpoints {
--mobile: 480px;
--tablet: 800px;
}

If we want to use them in JavaScript we can just get them form CSS and set a new value doing this:

var breakpoints = document.questySelector('.breakpoints');
var mobileBreakpoint = getComputedStyle(breakpoints).getPropertyValue('--mobile');

breakpoints.style.setProperty('--mobile', 450);

Conclusion

I very shortly illustrated some of the advantages that CSS custom properties provide but this is good enough for a little start. If you are thinking to start using them what you could do is starting to switch form SASS variables to pure CSS custom properties, or using CSS variables in SASS, or you also might switch from SASS to PostCSS with using the help from cssnext.
Hoping you enjoyed it, I wish you a pleasure CSS!

LEAVE A REPLY

you might also like