Using CSS Variables for Theming

Themes make a site customizable. The landscape of web and phone apps is starting to abide by an unwritten rule — people love options, and giving it to them lets them feel like they’re in control of their experience. Just like my 11th birthday party, a good theme can push your product from decent to memorable (pretty sure that theme was Pokemon, like they have been for the past 20 years).

Everyone loves a good party theme: The Roaring 20’s, Under The Sea, White Party, Mariah Carey B-Sides, 4th of July (Photo cred: https://berkscountyliving.com/)

How many apps or sites can you think provide some sort of configuration for the theme displayed? I remember back in college observing other students arguing over what The Best™ theme for Sublime Text was. And have you ever met someone who vehemently insisted you use Twitter in dark mode? (Sorry, but I refuse!) Or even the IDE that my company uses, IntelliJ, comes with a host of customization options to tailor the colors of my coding experience to exactly how I’d like to see every possible highlighted keyword.

So, how do we do this for a website?

The Old Way

Back in the oaky-smokey days, one way to accomplish this was to feed the browser multiple link tags and designating overrides with the rel attributes of “alternate stylesheet”. Your general styles will be written in the first file loaded in, and then any themed customizations will be in seperate CSS files imported later (to work with the Cascading part of CSS).

<link rel="stylesheet" type="text/css" title="main theme" href="http://mysite.com/css/main.css">
<link rel="alternate stylesheet" type="text/css" title="dark theme" href="http://mysite.com/css/dark.css">

From there, you could do something like using JavaScript to set whichever stylesheet to not use with the attribute “disabled”. Doing so means their values won’t override the base files, and you can persist this across sessions with the help of cookies or some other way of identifying a user’s preference.

Older browsers also had a means of letting the user manually change which stylesheet the browser would read by going through the view menu options. Looking at Chrome in 2020 while writing this, I don’t think browsers even give this option anymore, and I would be surprised if more than a small fraction of front-end devs knew you could do this at all. As this is no more than ancient knowledge at this point, I’m not going to go much further into how that works, but here’s an old article if you’re interested.

The biggest pitfall of doing it this way is that it requires a lot of duplicate code, depending on how much is changed between themes, and you may need multiple large CSS files, each with their own download.

A New Way

Thankfully, as technology progresses, so does the ease and convenience of a lot of tasks that were once tedious to pull off. One way to accomplish the same results as described above– in way less code, too — is by using CSS variables. This is by no means the only way to complete the task, but it is a fun one I’d like to share.

Variables in CSS are a fairly new feature that may seem like an old-hat to newer devs, but might be a welcome addition to the toolkit of engineers who have predominantly worked with styling preprocessors like SCSS or LESS (e.g. me). The main idea of this post isn’t to be a deep-dive into CSS variables, but mozzilla.org has great, readable, documentation about the feature.

One important thing to note is that CSS variables do not work on any version of Internet Explorer. If you are building for a client or environment that needs legacy browser support, this solution will not work for you.


With my IT consultant war flashbacks of IE7 support out of the way, let’s dig into it.

First, we need to make a cool HTML site and get some styling onto it.

Look at how good I am at this

One piece that I would like to call specific attention to is this one:

WAIT, no….. this one:

:root element with CSS variables for font size, background-color, font family, and font color

The :root pseudo-class selects the root element of the page that the CSS is being applied to. In almost every instance that I can think of when developing for a web browser, this is probably the <HTML> tag, but using the pseudo-class over the element in a style declaration has slightly higher specificity weight.

In this block I am declaring a few variables. These will be reusable pieces of code that I am using all over the CSS and would like to only have to change in one (1) spot. This is how they look in application:

A CSS snippet where variables are being used. This is taken from the CSS tab in the Codepen I embedded earlier in the post

As you’ve probably caught on to, overriding these variables will allow us to implement different themes to the website. Since I’ve already called out a number of properties that have large impacts on the visual design, making a new theme is as simple as giving –content-bg-color a new value.

Here’s my same site again, but now with a RaDiCaL 90’s color scheme. My inspiration was the pattern on these cups.

In this theme, I changed up the menu fonts, the font color for the entire site, and gave it the most obnoxious colors I could think of. Love it!

Let’s take a look at the two main code changes:

The first change is that I’ve given my <body> tag the class “radical-theme”. The second change is that in my CSS file, I’ve included a declaration with the class .radical-theme and in it I’ve overwritten the style variables that needed to be different. When I apply the “radical-theme” class to an element, it will pull the values from the second set of variable instances instead of the ones declared within :root .

Congrats, we now have a theme 🎉 !

Super neat, super great, super front-end, super css, etc etc but the one glaring issue with this demo is that it’s not dynamic.

If you’ve taken a look at the Codepen itself, you may have noticed that I actually have the code for a third theme ready to go, called .large-theme, but it is currently inaccessible. This makes the teal background color a little darker and ups the font size to 20px, but it just needs to be made accessible to a user.

To do this, I’ve modified the HTML in my working example to now include a <header> tag with a list of buttons named after the three of our themes, and made changes to the CSS to make this layout look “good”.

I also need to add some JavaScript to dynamically change the <body> tag class when a button is clicked. Let’s take a look at that:

//Get the list of theme buttons
let list = document.querySelectorAll('.theme-list button');

//set up our click handler for later
let onClick = (e)=> {
  //pull out the name from the button's data attributes
  let selectedTheme = e.target.dataset.name;
  let body = document.querySelector('body');
  
  //select the body tag and overwrite its applied classes 
  if(selectedTheme === 'base') {
    //in the case of the base theme, we actually don't want any classes applied at all
    body.classList = '';
  } 
  else {
    body.classList = `${selectedTheme}-theme`;
  }
};

//loop through our list of buttons and apply an event handler to each
for(let button of list) {
  button.addEventListener('click', onClick);
}

Basically, I am selecting all of the buttons within the <header>, giving them an on-click handler, and then determining which theme each button corresponds to by pulling out their data-name attribute. From there, I modify the body’s class and append “-theme” to the end of the name, or erase the class list if you’re going back to the default view.

There are many ways to do this, and it will look a little different if you’re doing this in a framework like React or Angular, but the general idea remains– on some action, change the class at the top-level tag and your page’s theme will update.

Here’s what it looks like all together!


Having the option to give your users choice in what theme they can view your site or app in makes it feel like a custom experience tailored to their wants. While the most common set are a pair of “dark” and “light” themes, you can provide as many as you have time to build, or even let your users customize their own. As long as your CSS variables are easy to understand and easy to overwrite, theming should be no sweat.

=> { }

Published by Fat Arrow Dev

I'm a UI developer in Boston.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: