Common Mistakes and Gotchas
CSS variables are sweet to work with but there are a few gotchas. You don't want to be making these mistakes and struggling with needless bugs.
Resolving Multiple Declarations
As with other properties, multiple declarations are resolved with the standard cascade.
Let’s see an example
/*define the variables*/
:root {
--color: blue;
}
div {
--color: green;
}
#alert {
--color: red;
}
/*use the variable on all elements*/
* {
color: var(--color);
}
With the variable declarations above, what will be the color of the following elements?
<p>What is my color? </p>
<div>and me? </div>
<div id='alert'>
What is my color too?
<p>color? </p>
</div>
Can you figure it out?
The Solution
The first paragraph will be blue
. There is no direct --color
definition set on a p
selector, so it inherits the value from :root
:root { --color: blue; }
The first div
will be green
. That’s kind of obvious. There’s a direct variable definition set on the div
div { --color: green; }
The div
with the ID of alert
will NOT be green. It will be red
#alert { --color: red; }
The ID has a direct variable scoping. As such ,the value within the definition will override the others. The selector #alert
Is more specific.
Finally, the p
within the #alert
will be … red
There’s no variable declaration on the paragraph element. You may have expected the color to be blue
owing to the declaration on the :root
element.
:root { --color: blue; }
As with other properties, CSS variables are inherited. The value is inherited from the parent, #alert
#alert { --color: red; }
Resolving Cyclic Dependencies
A cyclic dependency occurs in the following ways:
(a) when a variable depends on itself i.e uses a var()
that refers to itself
:root {
--m: var(--m)
}
body {
margin: var(--m)
}
(b) When two or more variables refer to each other
:root {
--one: calc(var(--two) + 10px);
--two: calc(var(--one) - 10px);
}
Do not create cyclic dependencies within your code.
What Happens with Invalid Variables?
Syntax errors are discarded, but invalid var()
substitutions default to either the initial or inherited value of the property in question .
Consider the following:
:root { --color: 20px; }
p { background-color: red; }
p { background-color: var(--color); }
As expected, --color
is substituted Into var()
but the property value, background-color: 20px
is invalid after the substitution. Since backgroud-color
isn’t an inheritable property, the value will default to its initial
value of transparent
Note that if you had written background-color: 20px
without any variable substitutes, the particular background declaration would have been invalid. The previous declaration will then be used.
Be Careful While Building Single Tokens
When you set the value of a property like so:
font-size: 20px
The 20px
is interpreted as a single token. A simple way to put that is, the value 20px
is seen as a single ‘entity’
You need to be careful when building single tokens with CSS variables.
For example, consider the following block of code:
:root {
--size: 20
}
div {
font-size: var(--size)px
}
You may have expected the value of font-size
to yield 20px
, but that is wrong.
The browser interprets this as 20 px
Note the space after the 20
Thus, if you must create single tokens, have a variable represent the entire token e.g --size: 20px
, or use the calc
function e.g calc(--size) * 1px
where --size
is equal to 20
Don’t worry if you don’t get this. I explain it better in a coming practical lessons.
Get hands-on with 1200+ tech skills courses.