Everything I know about CSS Variables Custom Properties
Brain dump about CSS Custom Properties, AKA CSS Variables
They are not variables
They are actually called CSS custom properties. Huh.
We’ll refer to them as variables for brevity.
Declaring variables
To declare new variables, you just add a new property that begins with --
, inside a ruleset:
:root { --color-main: #76fadd; --color-text: #282828; }
What is :root?
If you notice, in the previous example, in the previous MDN link and other tutorials, you’ll see that variables are declared inside a :root
, instead of html {...}
, body{...}
or whatever.
According to MDN, :root
is a pseudo-class that matches the root of the tree representing the document. In this case, it’s identical to the html
selector, except that its specificity is higher.
So why not use html then? Well, it’s perfectly fine.
CSS-Tricks explains this very clearly:
In an HTML document the
https://css-tricks.com/almanac/selectors/r/root/html
element will always be the highest-level parent, so the behaviour of:root
is predictable. However, since CSS is a styling language that can be used with other document formats, such as SVG and XML, the:root
pseudo-class can refer to different elements in those cases. Regardless of the markup language,:root
will always select the document’s top-most element in the document tree.
Using variables
.element { color: white; background: var(--color-main); }
Inheritance
CSS Variables are inherited exactly like normal CSS properties. They are, after all, CSS properties and not variables. In the following Pen you can see how children-1
can override --color-bg
declaration defined in it’s parent (.child
), but parent
can’t, since it has no access to it. --color-bg
declaration is “below” parent
it so it can’t cascade down to it.
Fallbacks
The first line of defense against undefined values is CSS’s cascading properties:
:root { --color-main: #76fadd; --color-text: #282828; } .element { background-color: #333333; background-color: var(--color-main); /* only interpreted by supported browsers*/ }
If the current browser doesn’t support CSS custom properties, it will ignore line 8 and apply a #333333
background. This is a very simple and isolated example, but it can be useful when some of these variables are generated and injected programmatically.
More importantly, fallback values work for browsers that do support custom properties. Fallback values are used when the given variable is not yet defined. The syntax is var(--variableName, defaultValue)
:
.element { background-color: var(--color-main, #333333); }
If --color-main
was not yet initialized or is by some reason invalid (maybe because it’s generated by user input), the background color of the element will be #333333
.
Dark mode
One of the perfect use cases for CSS variables is obviously making a dark mode UI. Here’s a quick Pen on how to achieve that very quickly:
See the Pen Dark Mode with CSS custom properties in 5 minutes by Nacho Toledo (@iign) on CodePen.
Congrats, now you have to maintain and test two versions of every element in your site.
Dark Mode CSS queries
In 2019 browsers started introducing the prefers-color-scheme
media query, in order to write CSS depending on the users’s OS setting. That means we can show a dark UI or tweak some styles for users that have a dark theme setting enabled on their OS:
:root { --color-bg: #fff; --color-text: #333; } @media (prefers-color-scheme: dark) { :root { --color-bg: #333; --color-text: #fff; } }
Browser support
Support is pretty good overall:
- Edge 16 (Oct 2017)
- Firefox 31 (Jul 2014)
- Chrome 49 (Mar 2016)
- Safari 9.1 (Mar 2016)
- Opera 36 (Mar 2016)
Work in progress
I’ll be updating this page soon. If this helped you clear up some thoughts or something seems off, let me know!
Useful links
- Using CSS custom properties (variables) — MDN
- :root (MDN)
- Support for CSS Variables (Custom Properties) — Can I Use
- Dark Mode in 5 minutes — CodePen
- prefers-color-scheme media query — Can I Use
- prefers-color-scheme — MDN