UI Development

CSS Variables


 

CSS Variables

Why?

Toady we use CSS preprocessor as a standard for the web development. The main reason for using preprocessor is that, it allows us to use the variables. Which avoid the need of coping and pasting the code which ultimate helps the developers to simplifies the development and refactoring.

Preprocessors are used to store Font Preferences, Font-size, Layout, Theme – mostly everything.

But preprocessors variables are also not perfect, it has some limitation’s:

  • They are not aware of the DOM structure.
  • We can’t change it dynamically.
  • Using the JavaScript we can’t able to read or change it’s value.

As, a silver bullet for all these, the community invented CSS custom properties often known as “CSS variables”.  The way they work are reflected in their names.

What?

As the name suggest, CSS variables allow us to use the variables directly in the CSS. Which will be very useful in reducing the repetition in CSS and along with it, it can also be used for powerful runtime effects like theme switching. With the help of the CSS variables we can :

  1. Localize the variables.
  2. Simplifies the development.
  3. Implementation of the DRY (DON’T REPEAT YOUR SELF ) principle.
  4. Maintenance.

All the above in one go.

These are the entities which holds the specific value and it is defined by the CSS author and that value can be used throughout the document. Mostly any website we developer develops contains a lot amount of CSS and in CSS a lot of values are repeated. For Example, the color attribute value might be used in hundreds of different places and if we need to change its value we then need a global search and then we can replace its value. But, custom properties or CSS variables allow us to store a value in one place and then referenced in different places. And it’s a lot more easy for us to remember the color name “red” instead of its hex code. Right!

CSS Variables are also officially a part of the CSS specification.

How we have the basic knowledge of the CSS Variable let’s explore how can we use it.

How?

Whenever we start learning a new preprocessor or a framework we need to learn a new syntax to use it. Same is the case with the CSS Variables. Each one has its unique syntax e.g. “$” in Sass and “@” in LESS.

Because it’s the way we can provide and use custom properties and our preprocessor will not compile them.

We can define the custom property just by adding the “–” (double hyphen) as a prefix to the custom property name. To use the variable we use var() CSS function.

Syntax:

element {
  --main-bg-color: brown;
}

Example:

/* Define CSS variables and scope */

:root {
 	--maincolor: black;
 	--secondarycolor: red;
}

/* Use CSS Variables */
body {
	 background: var(--maincolor);
 	color: white;
}
body p {
 	background: var(--secondarycolor);
}

The common practice to define custom property on :root pseudo class. In HTML :root is same as html but with higher preference.

The custom property names are case-sensitive i.e. “–maincolor” is different as compared to the “–Maincolor” property name.

Declaration and Use Case

What will happen if we are not sure about the custom property that we want to use has been defined or not?

Fallback Values:

In that scenario var() function is the handy way to pass the fallback value to it. This can be done by simply passing the fallback value as the second parameter to the var() function and anything from first comma to the  end of the function is considered a fallback value.

Example:

.box{
  --box-color:#4d4e53;
  --box-padding: 0 10px;

  /* 10px is used because --box-margin is not defined. */
  margin: var(--box-margin, 10px);
}
Just in case any browser that doesn’t support the Custom Properties then the fallback value won’t help. It’s just the backup for the browser which support the Custom Properties.

We can also reuse the already defined CSS variables value to define the new variables. Is’t cool!

Example:

<body>
    <div class="container">
        Hello!
    </div>
</body>
:root {
 	--darkfont: green; 
 	--darkborder: 5px dashed var(--darkfont);
}
/* Use CSS Variables */
.container {
 	color: var(--darkfont);
    border: var(--darkborder);
    min-height: 50px;
}

Output

Operations:

We developers always manipulate the variables by using some basic operations. CSS also provide’s us the way to do the same with the CSS Custom Variables. In CSS we can use cal() function to do the manipulations. What is does is, it’s make the browser to recalculate an expression after any change as been made to the custom properties.

Example:

<body>
    <div class="box1">
        Hello 1!
    </div>
    <div class="box2">
        Hello 2!
    </div>
    <div class="box3">
        Hello 3!
    </div>
    <div class="box4">
        Hello 4!
    </div>
    <div class="box5">
        Hello 5!
    </div>
</body>
:root {
 --indent-size: 10px;

  --indent-xl: calc(2*var(--indent-size));
  --indent-l: calc(var(--indent-size) + 2px);
  --indent-s: calc(var(--indent-size) - 2px);
  --indent-xs: calc(var(--indent-size)/2);
}
.box1 {
    margin-left: var(--indent-size);
}
.box2 {
    margin-left: var(--indent-xl);
}
.box3 {
    margin-left: var(--indent-l);
}
.box4 {
    margin-left: var(--indent-s);
}
.box5 {
    margin-left: var(--indent-xs);
}

Output

The problem arises when we use unit-less values. In that case the var() function alone won’t work. Then we can use cal() function with the var() function.

Example:

:root{
  --spacer: 10;
}

.box{
  padding: var(--spacer)px 0; /* DOESN'T work */
  padding: calc(var(--spacer)*1px) 0; /* WORKS */
}

Scope and Inheritance

As we know the scope of closure is:

  1. Its own space i.e. variables defined inside its braces.
  2. Variables of the outer function’s.
  3. The global variables (e.g. Windows variables).

If we talk about the Sass preprocessor, in Sass the variables scope is fully depend how we write our code i.e. code structure.

But the CSS Custom Properties are inherited by default i.e. they are cascade like other CSS properties. But in CSS we also can’t define the CSS variable  outside the closure (not a valid CSS). So, the global scope for the CSS custom property is the :root scope.

Example: 

HTML

global
<div class="enclosing">
  enclosing
  <div class="closure">
    closure
  </div>
</div>

Now the CSS

:root {
  --globalVar: 10px;
}

.enclosing {
  --enclosingVar: 20px;
}

.enclosing .closure {
  --closureVar: 30px;

  font-size: calc(var(--closureVar) + var(--enclosingVar) + var(--globalVar));
  /* 60px for now */
}

Output

What will happen if we change the value of the CSS Custom Properties?

If we change the value of the CSS Custom Property then, any changes applied to it will automatically applied to all instance of it i.e. the value get’s recalculated. Where as in other preprocessor this won’t happen.

What happen in Sass or other Preprocessors:

Example(Sass):

.closure {
  $closureVar: 30px; // local variable
  font-size: $closureVar +$enclosingVar+ $globalVar;
  // 60px, $closureVar: 30px is used

  $closureVar: 50px; // local variable
}

In Sass this will have no effect.

Output

But in CSS the value gets recalculated.

Example:

.enclosing .closure {
  --closureVar: 30px;

  font-size: calc(var(--closureVar) + var(--enclosingVar) + var(--globalVar));
  /* 80px for now, --closureVar: 50px is used */

  --closureVar: 50px;
}

Output

The browser will recalculate all the variables and calc() expressions.

Preprocessors are not Aware of the DOM Structure:

Let’s take an example to prove this point, suppose we want to use the default font-size property value for the block, expect where “highlighted” class is present.

Example:

HTML

<div class="default">
  default
</div>

<div class="default highlighted">
  default highlighted
</div>

Using CSS Custom Property

.highlighted{
  --highlighted-size: 30px;
}

.default {
  --default-size: 10px;

  /* Use default-size, except when highlighted-size is provided. */
  font-size: var(--highlighted-size, var(--default-size));
}

In the above example the second div contains the highlighted class along with the default class and the value of the font-size will be set to the  30px because the second parameter of the var() function is the fallback value which  means it’s only be used when the first parameter is not valid or not provided. But here the first parameter is present and hence it will set the font-size value to 30px.

Output:

Using the Sass Preprocessor

.highlighted {
  $highlighted-size: 30px;
}

.default {
  $default-size: 10px;

  /* Use default-size, except when highlighted-size is provided. */
  @if variable-exists(highlighted-size) {
    font-size: $highlighted-size;
  }
  @else {
    font-size: $default-size;
  }
}

Output:

The difference between the two output is because of the fact that in Sass all the calculations and processing happen at the time of the compilation and also it relies on the code structure and unaware of the DOM structure

This is the other advantage of the CSS Custom Properties that they are aware of the DOM structure and are dynamic.

What happens with the Invalid variables?

How does the browser react when it encounter any invalid value of the CSS Custom property e.g. say, color: 16px;

Lets try to understand the how will the browser respond to it.

Example:

<p>This paragraph is initial black.</p>

CSS part:

:root { 
	--text-color: 16px; 
	} 
p { 
	color: blue;
 } 
p { 
	color: var(--text-color);
 }

Now, as var() function will work is, it will replace “var(–text-color)” with its value i.e. 16px, which is invalid. Now browser will do one of the following two things.

  1. It will check whether the property color is inheritable, if not
  2. It will set its value to its default initial value i.e. black.

Output:

This paragraph is initial black.

Browser Compatibility

Conclusion

We have learn about the new but powerful CSS Custom Properties, their syntax, how they are different from the other preprocessor variables, their advantages over them and how we can use them. We also learned about their compatibility in modern browser’s.

And this is the right time to start using CSS Custom Properties.

I hope you will find this blog useful!

References

  1. https://developer.mozilla.org/en-US/docs/Web/CSS/Using_CSS_custom_properties
  2. https://www.smashingmagazine.com/2017/04/start-using-css-custom-properties/#top
  3. https://blog.yipl.com.np/understanding-css-variables-74fdb6e7ef54

About The Author