Getting to grips with CSS variables
Oct 21, 2020
If you have ever used JavaScript variables then the concept of CSS variables should feel pretty familiar.
- You set a variable
- You use the variable
CSS variables follows this same pattern, but the language is slightly different.
1body { --my-variable: red; } h1 { color: var(--my-variable); }
What is happening here? Firstly we set the variables - essentially they are custom properties. We use --
before the variable name to make it a variable. Then we use the variable by using var(--variable-name)
.
1<body> <!-- --my-variable: red; --> <h1>CSS - Carl's Super Styles!</h1> <!-- colour: red --> </body>
Usually most variables are set on the pseudo element ::root
so that every HTML element will be encompassed by it.
1:root { --color: red; --size: 20px; --background: #222; --padding: 1em; }
Scope of variables
CSS variables are scoped to their ancestors (parents, though grandparents to the root pseudo element).
Variables can be changed by child elements, but only apply further downstream in the DOM. That means that variables set in different branches of the DOM are only applicable to that tree. A bit like genetics, you only share the same genes from shared ancestors.
Changing a variable
1:root { --my-variable: red; } body { --my-variable: blue; } h1 { color: var(--my-variable); }
Here the root color of red will be overridden by the my-variable
on the body, so the h1
ends up with blue text.
1<!-- :root --my-variable: red; --> <body> <!-- --my-variable: blue; --> <h1>CSS - Carl's Super Styles!</h1> <!-- colour: blue --> </body>
The Same variable in different trees
In the following example the root --color
variable is black. We then set the classes of .red
and .blue
to red and blue respectively. Then we create a h2
to consume the --color
variable.
1:root { --color: black; } .red { --color: red; } .blue { --color: blue; } h2 { color: var(--color); }
The h2
that is not wrapped by either one of red
or blue
inherits the value for the root color variable which is black. Both red
and blue
redefine the value of the variable and the h2 within their trees will be the relevant color.
1<h2>Black</h2> <div class="red"> <h2>Red</h2> </div> <div class="blue"> <h2>Blue</h2> </div>
Media queries
In the pre variable days of css we did this:
1.red { font-size: 1em; } .blue { font-size: 1em; } @media screen and (min-width: 32em) { .red { font-size: 2em; } .blue { font-size: 2em; } }
With variables we can replace the hardcoded values with values set at the :root
.
1:root { --mobile-size: 1em; --desktop-size: 2em; } .red { width: var(--mobile-size); } .blue { width: var(--mobile-size); } @media screen and (min-width: 32em) { .red { width: var(--desktop-size); } .blue { width: var(--desktop-size); } }
We can do one better and move the media queries to the root, cutting out the need to add extra code for developers to maintain. Media queries will all be managed in 1 place too!
1:root { --font-size: 1em; } @media screen and (min-width: 32em) { :root { --font-size: 2em; } } .red { width: var(--font-size); } .blue { width: var(--font-size); }
Final notes and thoughts
One of the important things to remember about CSS variables v1 is that the CSS spec states that var
can only be used to set properties, so you cannot use them as part of a media query.
Thevar()
function can be used in place of any part of a value in any property on an element. Thevar()
function can not be used as property names, selectors, or anything else besides property values. (Doing so usually produces invalid syntax, or else a value whose meaning has no connection to the variable.)
That means that the following will currently not work.
1@media screen and (min-width: var(--min-width-desktop)) { /* ... the content */ }
This is subject to change as later versions of the CSS spec are going to be rolled out in the future.
Even without the current ability to use variables as media queries values, the extra control gained by having reusable values for regular CSS properties is invaluable. With the vast majority of browsers supporting CSS variables then there really is no excuse not to use them in your daily workflow.