CSS Custom Properties

Add Variables to Your CSS

Geoffrey Crofte

UX/UI Web Designer at Maltem (Foyer)

  • geoffrey.crofte.fr
  • creativejuiz.fr
  • @geoffrey_crofte

You can follow me on Twitter, my personal website and my blog, CreativeJuiz.

Overview

Overview

  • What are Custom Properties?
  • Quick start with CSS Variables.
  • Why CSS C.P. instead of Sass variables?
  • Use cases & Demos
  • Takeaways

What are Custom Properties?

What are Custom Properties? So first, let’s try do define what is a custom properties.

What are Custom Properties?

And please, everybody call them CSS Variables :) You should do so.

This not about

$color: #bada55; @color: #bada55;

This presentation is not about Sass or LESS variables. CSS Variables have nothing to do with Sass or LESS variables.

This is more about…

This is more about something like the f irst CSS variable you might already know(?) currentColor. This variable comes directly f rom the SVG specif ication and perfectly works in HTML. In this example the colour of the text and borders depends on the current def ined color.

http: //bit.ly/csscurrentcolor

This is more about magic

I change the value of colour property and tadaaaa Magic happens. But…

But this is not about currentColor neither

This is not about currenColor neither or any predefined CSS variables, it’s about Custom Variables. To better understand Custom Properties, I spent free hours in the documentation. So, I did.

Custom Property definition

A custom property is any property whose name starts with two dashes […] like --foo

This is one of the first description of a CustomProperty by The W3C. Really helpful, kinda like it… do you? Don’t worry, there are more helpful words later…

Custom Property definition

Custom properties are solely for use by authors and users; CSS will never give them a meaning beyond what is presented here. Or not…

Custom Property definition

But THAT, is a teaser. In fact, absolutely not. The very first time you really read the word “Variable” is inside an example of the documentation.

W3C Definition Extract

Right here. “Custom properties def ine variables”… yay. All of that to say: custom properties are in fact variables for CSS.

What the Spec says…

  • Custom properties define variables
  • Variables are referenced with the var() notation
  • They are Case-Sensitive
  • Their value is “extremely permissive”

Joke behind us, let summarize the documentation, in some words. 2) …you can get a variable with that function, 3) …you have to know that, 4) …I mean, really, you’ll see.

In other words…

In other words, do the fuuuuck you want with them, if it’s not understandable by the CSS engine of your browser, the return value will be a silent error.

How to us CSS Variables?

How to use CSS Variables? Let’s go with some code examples to better understand the syntax.

CSS Declaration

-- variableName :

value ; CSS Declaration :root { } First you need to declare it. I used :root pseudo element that refers to the HTML element for web page, or SVG element for SVG document, for example. It’s a way to declare a variable globally. You might be thinking why a double dash? Remember the pref ixed properties -moz- to address a custom property to a specif ic browser. It’s the same idea but with an empty pref ix to address all the browsers.

CSS Declaration v2

-- variableName :

value ; CSS Declaration .element { } Another way to declare variable is locally. Here inside an .element declaration. The value of this variable will be available only for this element and its children, and the children of its children.

CSS Variable Use

property:

var(

variableName ) ; .element { } CSS Use Then you can get the value of your variable with the var() function.

Quick Example of use

Quick Example of use Here a sample of code. Declare link color in root, Use var() function to get the colour value, and that’s all, you know everything about CSS Variables, thanks for coming :D

Why CSS instead of Sass Variables?

Why CSS instead of Sass Variables? Ok. Kidding. Now you might be thinking why? “I can do the same with Sass variables”. Yep, you’re right, but not really.

Computation

The main issue with Sass (or LESS) variables: They have to be computed to get their value. Computation The main issue with Sass is that Sass has to be computed to generate CSS, and sometimes computation leads to a big amount of code. Right?

CSS Variables are alive

CSS Variables are alive CSS Variables are alive, they are not computed. Here I will change one CSS variable declared at the root level. And the magic happens. It’s something really useful when it comes the moment of debugging things. Editing variables f rom the dev tool is a real time saver. You can’t do that with Sass.

JavaScript can access them

JavaScript can access them JavaScript can access them, edit them or set theme quite easily. JavaScript can’t access Sass variables.

Media Queries ❤️ CSS Variables

Media Queries ❤ CSS Variables Imagine a website you build with a global margin and padding of f ifteen pixels. When your screen is big enough, you increase the margins to forty pixels. 1) With Sass you would probably have to do something like that. Or perhaps by using mixins, which is way more complex. 2) With CSS Variables, you can do something like that.

Media Queries ❤️ CSS Variables

Media Queries ❤ CSS Variables Imagine a website you build with a global margin and padding of f ifteen pixels. When your screen is big enough, you increase the margins to forty pixels. 1) With Sass you would probably have to do something like that. Or perhaps by using mixins, which is way more complex. 2) With CSS Variables, you can do something like that.

CSS Variables are inherited

CSS Variables are inherited CSS variables are inherited. Let’s see that with this little dirty demo. Let’s say I have one link alone, and 2 links inside a nav element. 1) I declare a link variable with purple value. Nothing happens, yet. 
 2) I declared a color by default for links with my variable as value. What will happen? 
 All the links turn purple. 
 3) Then I declare a new value for my variable inside a new declaration, and I target links into my nav element. What will happen? 
 Only nav links turn salmon. 
 4) And now? See? I just removed “a” f rom my last declaration. What will happen? 
 Nothing happens. Links inside nav are still salmon because custom properties are inherited.

CSS Variables are inherited

CSS Variables are inherited CSS variables are inherited. Let’s see that with this little dirty demo. Let’s say I have one link alone, and 2 links inside a nav element. 1) I declare a link variable with purple value. Nothing happens, yet. 
 2) I declared a color by default for links with my variable as value. What will happen? 
 All the links turn purple. 
 3) Then I declare a new value for my variable inside a new declaration, and I target links into my nav element. What will happen? 
 Only nav links turn salmon. 
 4) And now? See? I just removed “a” f rom my last declaration. What will happen? 
 Nothing happens. Links inside nav are still salmon because custom properties are inherited.

CSS Variables are inherited

CSS Variables are inherited CSS variables are inherited. Let’s see that with this little dirty demo. Let’s say I have one link alone, and 2 links inside a nav element. 1) I declare a link variable with purple value. Nothing happens, yet. 
 2) I declared a color by default for links with my variable as value. What will happen? 
 All the links turn purple. 
 3) Then I declare a new value for my variable inside a new declaration, and I target links into my nav element. What will happen? 
 Only nav links turn salmon. 
 4) And now? See? I just removed “a” f rom my last declaration. What will happen? 
 Nothing happens. Links inside nav are still salmon because custom properties are inherited.

CSS Variables are inherited

CSS Variables are inherited CSS variables are inherited. Let’s see that with this little dirty demo. Let’s say I have one link alone, and 2 links inside a nav element. 1) I declare a link variable with purple value. Nothing happens, yet. 
 2) I declared a color by default for links with my variable as value. What will happen? 
 All the links turn purple. 
 3) Then I declare a new value for my variable inside a new declaration, and I target links into my nav element. What will happen? 
 Only nav links turn salmon. 
 4) And now? See? I just removed “a” f rom my last declaration. What will happen? 
 Nothing happens. Links inside nav are still salmon because custom properties are inherited.

CSS Variables are inherited

CSS Variables are inherited CSS variables are inherited. Let’s see that with this little dirty demo. Let’s say I have one link alone, and 2 links inside a nav element. 1) I declare a link variable with purple value. Nothing happens, yet. 
 2) I declared a color by default for links with my variable as value. What will happen? 
 All the links turn purple. 
 3) Then I declare a new value for my variable inside a new declaration, and I target links into my nav element. What will happen? 
 Only nav links turn salmon. 
 4) And now? See? I just removed “a” f rom my last declaration. What will happen? 
 Nothing happens. Links inside nav are still salmon because custom properties are inherited.

CSS Variables are inherited

CSS Variables are inherited CSS variables are inherited. Let’s see that with this little dirty demo. Let’s say I have one link alone, and 2 links inside a nav element. 1) I declare a link variable with purple value. Nothing happens, yet. 
 2) I declared a color by default for links with my variable as value. What will happen? 
 All the links turn purple. 
 3) Then I declare a new value for my variable inside a new declaration, and I target links into my nav element. What will happen? 
 Only nav links turn salmon. 
 4) And now? See? I just removed “a” f rom my last declaration. What will happen? 
 Nothing happens. Links inside nav are still salmon because custom properties are inherited.

Demos & Use Cases

Demos & Use Cases Let’s go with some use cases and demos.

http: //bit.ly/cssvargradient The f irst demo is for the Wahoo effect. It’s a pointer tracking effect where positioning if done with CSS and…

Mouse position

Mouse position …and 6 lines of JS. Sorry if I disappoint you, but that’s all for JS.

CSS Transformation

CSS Transformation And… yeah sorry CSS can be really verbose sometimes. So here, the 3 things you have to see are… 1) I’m setting up 2 variables I need to position my halo 2) Then I position the element with a simple calculation, 3) Finally, the interesting part, I transform my element by translating it using variables declared with JS. The size of the pseudo-element is equal to zero at this point. ok?

CSS Transformation

CSS Transformation And… yeah sorry CSS can be really verbose sometimes. So here, the 3 things you have to see are… 1) I’m setting up 2 variables I need to position my halo 2) Then I position the element with a simple calculation, 3) Finally, the interesting part, I transform my element by translating it using variables declared with JS. The size of the pseudo-element is equal to zero at this point. ok?

CSS Transformation

CSS Transformation And… yeah sorry CSS can be really verbose sometimes. So here, the 3 things you have to see are… 1) I’m setting up 2 variables I need to position my halo 2) Then I position the element with a simple calculation, 3) Finally, the interesting part, I transform my element by translating it using variables declared with JS. The size of the pseudo-element is equal to zero at this point. ok?

CSS Transformation

CSS Transformation And… yeah sorry CSS can be really verbose sometimes. So here, the 3 things you have to see are… 1) I’m setting up 2 variables I need to position my halo 2) Then I position the element with a simple calculation, 3) Finally, the interesting part, I transform my element by translating it using variables declared with JS. The size of the pseudo-element is equal to zero at this point. ok?

CSS Transformation

CSS Transformation And when the user starts hovering the element, we give it a real size.

  1. But instead of doing that, I’ll do that.
  2. Because remember? We had dimensions declared like that.

CSS Transformation

CSS Transformation And when the user starts hovering the element, we give it a real size.

  1. But instead of doing that, I’ll do that.
  2. Because remember? We had dimensions declared like that.

CSS Transformation

CSS Transformation And when the user starts hovering the element, we give it a real size.

  1. But instead of doing that, I’ll do that.
  2. Because remember? We had dimensions declared like that.

Now you're wondering…

Why not pushing transformations directly in JavaScript? Now you’re wondering… So f inally, why not pushing transformations directly in JavaScript? Yeah, right, why not? This code is perfectly functional. 1) You will have to maintain styles inside JS. This is not the purpose of JS, and in an era of Design System, it’s a lack of portability. 2) Even declared in JS, CSS variables are inherited, (in that case we don’t really care, I agree) 3) It’s simply a philosophy, CSS is for styling, JS is not, 4) It’s Futur proof, let the CSS engine handle that part. Just send CSS variable values to CSS with JS, that’s all.

Now you're wondering…

Why not pushing transformations directly in JavaScript? Now you’re wondering… Maintainability / Portability 
 style=“transform…” is dirty. Period. 
 So f inally, why not pushing transformations directly in JavaScript? Yeah, right, why not? This code is perfectly functional. 1) You will have to maintain styles inside JS. This is not the purpose of JS, and in an era of Design System, it’s a lack of portability. 2) Even declared in JS, CSS variables are inherited, (in that case we don’t really care, I agree) 3) It’s simply a philosophy, CSS is for styling, JS is not, 4) It’s Futur proof, let the CSS engine handle that part. Just send CSS variable values to CSS with JS, that’s all.

Now you're wondering…

Why not pushing transformations directly in JavaScript? Now you’re wondering… Maintainability / Portability 
 style=“transform…” is dirty. Period. 
 Inheritance 
 style=“transform…” do not make --x and --y inherited. So f inally, why not pushing transformations directly in JavaScript? Yeah, right, why not? This code is perfectly functional. 1) You will have to maintain styles inside JS. This is not the purpose of JS, and in an era of Design System, it’s a lack of portability. 2) Even declared in JS, CSS variables are inherited, (in that case we don’t really care, I agree) 3) It’s simply a philosophy, CSS is for styling, JS is not, 4) It’s Futur proof, let the CSS engine handle that part. Just send CSS variable values to CSS with JS, that’s all.

Now you're wondering…

Why not pushing transformations directly in JavaScript? Now you’re wondering… Maintainability / Portability 
 style=“transform…” is dirty. Period. 
 Inheritance 
 style=“transform…” do not make --x and --y inherited. It’s a philosophy 
 CSS is for styling. JS is not. 
 So f inally, why not pushing transformations directly in JavaScript? Yeah, right, why not? This code is perfectly functional. 1) You will have to maintain styles inside JS. This is not the purpose of JS, and in an era of Design System, it’s a lack of portability. 2) Even declared in JS, CSS variables are inherited, (in that case we don’t really care, I agree) 3) It’s simply a philosophy, CSS is for styling, JS is not, 4) It’s Futur proof, let the CSS engine handle that part. Just send CSS variable values to CSS with JS, that’s all.

Now you're wondering…

Why not pushing transformations directly in JavaScript? Now you’re wondering… Maintainability / Portability 
 style=“transform…” is dirty. Period. 
 Inheritance 
 style=“transform…” do not make --x and --y inherited. It’s a philosophy 
 CSS is for styling. JS is not. 
 Futur proof 
 Let the CSS engine handle that part. So f inally, why not pushing transformations directly in JavaScript? Yeah, right, why not? This code is perfectly functional. 1) You will have to maintain styles inside JS. This is not the purpose of JS, and in an era of Design System, it’s a lack of portability. 2) Even declared in JS, CSS variables are inherited, (in that case we don’t really care, I agree) 3) It’s simply a philosophy, CSS is for styling, JS is not, 4) It’s Futur proof, let the CSS engine handle that part. Just send CSS variable values to CSS with JS, that’s all.

Another Wahou demo

http: //bit.ly/cssvargradient2 A little demonstration with the same principle but applied to a dynamic gradient color on a text.

CSS Transformation

CSS Transformation The JavaScript code is quite the same than previously, but I only need the X value. I applied the transformation directly inside the linear-gradient. The position of each colour in that gradient is calculated thanks to the calc() function and a little modif ier. That’s all. The rest are the properties to apply gradient to text.

Themable interfaces

Themable interfaces Another good way to use CSS variables is when it comes the time to create variation of components. Imagine a bunch of elements like titles, texts and buttons. Usual, right?

  1. First you set your “default styles”.
  2. Then you create variations depending on the context. Here a dark background.

Themable interfaces

Themable interfaces Another good way to use CSS variables is when it comes the time to create variation of components. Imagine a bunch of elements like titles, texts and buttons. Usual, right?

  1. First you set your “default styles”.
  2. Then you create variations depending on the context. Here a dark background.

Themable interfaces code

Themable interfaces To do that, you can do it the old overflowing fashion way. With a lot of duplicated code. 1) Or you can use CSS variables to declare a bunch of initial variables: 2) Then change only what your need for your variation.

Themable interfaces code with variables

Themable interfaces To do that, you can do it the old overflowing fashion way. With a lot of duplicated code. 1) Or you can use CSS variables to declare a bunch of initial variables: 2) Then change only what your need for your variation.

Themable interfaces code with variables

Themable interfaces To do that, you can do it the old overflowing fashion way. With a lot of duplicated code. 1) Or you can use CSS variables to declare a bunch of initial variables: 2) Then change only what your need for your variation.

Accessibility Example

Accessibility Example With the same principle, you can create alternate Stylesheets to load only when it’s needed.

Accessibility Example

Accessibility Example You just need to set a class on the root element or load a specif ic stylesheet with redef ined variables.

Responsive

Responsive Again with the same principle, all the responsive work is now easier.

  1. Declare your query and change only variables you need to edit.

Responsive

Responsive Again with the same principle, all the responsive work is now easier.

  1. Declare your query and change only variables you need to edit.

CSS Variables are CSS properties

Further Takeaways Now you know more CSS Variables, let’s go further with a few tips.

CSS Variables are CSS properties

-- variableName : value !important ; :root { } CSS Variables are CSS properties CSS Variables are actual CSS properties, they are ruled by the same principles. So yeah, if you need to override a value for sure, you can also use !important.

(kind of) Silent error

-- variableName : lolilol; :root { } (kind of) Silent error If you set a non-CSS-compatible value for you property, CSS will fallback to a silent error. A non valid value makes var() function return a new type of error.

You can't "build up" values

-- spacing : 20 ; :root { } You can’t “build up” values. margin : var(--spacing) px ; :root { } Doesn’t work You cannot build up values with separate numbers and units.

  1. That doesn’t work. 
 The value has to be a single, valid, unambiguous CSS value. It’s because CSS doesn’t have concatenation, concatenation only works with “content” property. I heard of a concatenation function in a next version, later, maybe, but not for now.

Strange behaviour

-- spacing :; :root { } Strange behaviour

spacing :

; :root { } Invalid Valid Yeah, that’s a space caracter. The f irst variable is invalid. The second is valid, it’s equal to a “space” caracter value. Don’t ask.

Fallbakc value

Fallback value var(

variableName, default ) ; You can add a parameter which provides a fallback if variableName is not def ined, “default” value will be used instead.

Fallback value

Fallback value A little exercise for you, ready? 1) What happens if my browser doesn’t support CSS Variables? 
 Purple happens. 
 2) What happens if my variable if not set? 
 Salmon, my fallback happens. 
 3) If I set my variable, you get the right color. 
 4) What if the variable value is invalid? Like 5 degrees. 
 var() fallback to the initial value, which is none-transparent for background. 
 The real error for the CSS engine is “Invalid at computed value time”.

Fallback value

Fallback value Doesn’t support var() A little exercise for you, ready? 1) What happens if my browser doesn’t support CSS Variables? 
 Purple happens. 
 2) What happens if my variable if not set? 
 Salmon, my fallback happens. 
 3) If I set my variable, you get the right color. 
 4) What if the variable value is invalid? Like 5 degrees. 
 var() fallback to the initial value, which is none-transparent for background. 
 The real error for the CSS engine is “Invalid at computed value time”.

Fallback value

Fallback value Doesn’t support var() Fallback is there A little exercise for you, ready? 1) What happens if my browser doesn’t support CSS Variables? 
 Purple happens. 
 2) What happens if my variable if not set? 
 Salmon, my fallback happens. 
 3) If I set my variable, you get the right color. 
 4) What if the variable value is invalid? Like 5 degrees. 
 var() fallback to the initial value, which is none-transparent for background. 
 The real error for the CSS engine is “Invalid at computed value time”.

Fallback value

Fallback value Doesn’t support var() Fallback is there A little exercise for you, ready? 1) What happens if my browser doesn’t support CSS Variables? 
 Purple happens. 
 2) What happens if my variable if not set? 
 Salmon, my fallback happens. 
 3) If I set my variable, you get the right color. 
 4) What if the variable value is invalid? Like 5 degrees. 
 var() fallback to the initial value, which is none-transparent for background. 
 The real error for the CSS engine is “Invalid at computed value time”.

Fallback value

Fallback value Doesn’t support var() Fallback is there --bgColor Value A little exercise for you, ready? 1) What happens if my browser doesn’t support CSS Variables? 
 Purple happens. 
 2) What happens if my variable if not set? 
 Salmon, my fallback happens. 
 3) If I set my variable, you get the right color. 
 4) What if the variable value is invalid? Like 5 degrees. 
 var() fallback to the initial value, which is none-transparent for background. 
 The real error for the CSS engine is “Invalid at computed value time”.

Fallback value

Fallback value Doesn’t support var() Fallback is there --bgColor Value A little exercise for you, ready? 1) What happens if my browser doesn’t support CSS Variables? 
 Purple happens. 
 2) What happens if my variable if not set? 
 Salmon, my fallback happens. 
 3) If I set my variable, you get the right color. 
 4) What if the variable value is invalid? Like 5 degrees. 
 var() fallback to the initial value, which is none-transparent for background. 
 The real error for the CSS engine is “Invalid at computed value time”.

Fallback value

Fallback value Doesn’t support var() Fallback is there --bgColor Value Transparent A little exercise for you, ready? 1) What happens if my browser doesn’t support CSS Variables? 
 Purple happens. 
 2) What happens if my variable if not set? 
 Salmon, my fallback happens. 
 3) If I set my variable, you get the right color. 
 4) What if the variable value is invalid? Like 5 degrees. 
 var() fallback to the initial value, which is none-transparent for background. 
 The real error for the CSS engine is “Invalid at computed value time”.

Variable as Fallback

Variable as Fallback var(

var1, var(

var2, default )) ; You also can have variable as variable fallback.

Variable as Fallback

Variable as Fallback var(

var1, var(

var2, var(

var3, var(

var4, var(

var5, default ))))) ; So yeah, this is valid and functional.

You can't cycle with variables

You can’t cycle with variables Cycle makes the variable invalid. You just cannot do this, CSS is not strong enough :D

  1. But you can actually do that, it works.

You can't cycle with variables

You can’t cycle with variables Cycle makes the variable invalid. You just cannot do this, CSS is not strong enough :D

  1. But you can actually do that, it works.

Support Testing

@supports ( color:

var(

) )

{ … } Support Testing And to go further, if you have to support old browsers, you can check the support using @supports

  • You can use any property (not only color)
  • You don’t have to include an actual variable name, you can just use double-dash.

Compatibility and Support

Compatibility CSS Variables are off icially in Candidate Recommandation, and are now supported by almost Eighty Eight percent of users. Depending on your users you should be able to use them on production.

Polyfills

Polyf ills https://github.com/ aaronbarker/css-variables-polyf ill And just in case you need to support Internet Explorer, some people are working on that polyf ill.

Some resources

“CSS Custom Properties” — @geoff rey_crofte Some resources CSS Variable Secrets (Lea Verou Smashing Conf. 2017) CSS Custom Properties (CCSWG W3C documentation) CSS Mouse Tracking Gradient (Gradient on Text demonstration) CSS Variable Tutorials (A series of 4 short videos about CSS Variables) Here some resources that helped me better understand CSS Variables.

Thanks! And thank you to the Wort for having us.

“CSS Custom Properties” — @geoff rey_crofte Geoff rey Crofte geoffrey.crofte.fr creativejuiz.fr UX/UI Web Designer at Maltem (Foyer) @geoffrey_crofte

55