
Theming using CSS Vars with tips
There was a time when a1024 pixel grid was all we had to develop our web apps for, that time is long gone. And there was a time when the colors in our app were fixed and a direct copy from a PSD, that time too is long gone. Users expect applications to be fluid and change to fit them and their devices. Using a dark Windows theme? The app should do the same. Accessibility is also extremely important for developers and theming can help us serve users suffering from CVD (color vision deficiency).
This post will show a quick and easy way to implement themes to your front end applications.
The old way of doing it
Before I show you the code let’s take a glance at the past. During the jQuery era we used to implement themes by appending a className to the body of the HTML. For example the class .red would act as the overriding CSS selector. The code would look something like this:
JS:
document.getElementByTagName('body').className.add('red')
CSS:
.background { background-color: white; } .red .background { background-color: red;
In this example once the className red is added to the body, all selectors underneath will change color.
The problem with nested classes
The problem this creates is two fold. For one maintenance of the app is more complicated as we have to double each class that can change color. If your app has 1000 classes, that will be 2000 once you are done. These are CSS classes we need to maintain and change if the code comes back from design or UX. Of course we could use SCSS maps and functions for this purpose and we probably should, but it’s still complexity we will need to manage.
Secondly it doesn’t scale at all. Our CSS code becomes larger with every theme we add to the stack. 30kb load becomes ~36kb. (It doesn’t quite double as we only have to declare color changes), but it does add up quickly. 12 themes becomes 30 + 6 * 12 = 102kb. That’s a 4x size penalty.
Solution
The solution comes from adding CSS variables , which is now supported by practically all the browser (CSS Variables (Custom Properties) | Can I use… Support tables for HTML5, CSS3, etc)
First declare your theme. My one rule is that keys should not change and describe its use very well. So for example a HTML card could have the following colors:
cardBackground: #ffffff cardBorder: #444444 cardText: #444444
A worse solution would be to do this:
background: #ffffff border: #444444 text: #444444
While this is also fine, it now becomes impossible to change the card background independent from the general app background. This could be totally fine but think about the sensible overrides ahead of time.
In your code the styling should look something like this:
HTML:
:root { --cardBackground: #ffffff; ---cardBorder: #444444, --cardText: #444444 }
CSS
.card { background-color: var(--cardBackground, #ffffff) }
JS
document.getElementByTagName('body').appendStyle('new values here')
First we inject all our variables with a value in the root of the HTML. This makes it applicable to all of our CSS classes. Although you can in theory append the variables to a nested class (div, .card etc). That would only expose these variables to every child elements and we probably don’t want to do that.
Secondly we reference the classes in our class, and add a fallback value if the variable could not be found. That is the second value in var(—).
Why this rocks
This is awesome because we can now keep our CSS dry and clean and add infinite theming solutions without increasing the size of our CSS. Secondly the colors can change in real time without the need for a reload or fetching additional files. Check this example repo to see the code in action.
Concluding
Theming is an increasingly important aspect of application development. It can solve accessibility issues, offering QOL (quality of life) improvements such as dark mode, or be a solution to offering a white label product for vendors to brand.
We should accomplish this by avoiding nested CSS classes and instead use CSS variables. These can be added to the HTML and change during runtime. This tricks enables us to deliver a clean theming solution and infinite scalability for our web apps. Thank you CSS variables :)