Website Theming With CSS Custom Properties

You may have noticed that you can now toggle between dark and light themes on the site. This was done using CSS custom properties (aka CSS variables). In this post you’ll see how you can achieve something similar using only CSS and a touch of JavaScript.

The power of custom properties in CSS really shines here because, unlike with variables defined using a CSS preprocessor, they are dynamic and their values can be changed or overwritten at any point in time and as response to user input. When the value of a variable is changed or overwritten, all elements that use the variable will automatically reflect the change.

A CSS variable theming example

First you’ll have to do a bit of grunt work and extract all the colors that you want to make themable into CSS custom properties. Let’s say we’re starting with the following styles:

body {
  background: white;
  color: #555;  
}

a, a:link {
  color: #639A67;
}
a:hover {
  color: #205D67;
}

You’ll then define the custom properties as such:

:root {
  --bg: white;
  --text-color: #555;
  --link-color: #639A67;
  --link-hover: #205D67;
}

With this in place, your CSS rules can now be changed to something like the following:

body {
  background: var(--bg);
  color: var(--text-color);  
}

a, a:link {
  color: var(--link-color);
}
a:hover {
  color: var(--link-hover);
}

Applying the theme will be as simple as adding a class to the body element, so you’ll define the theme’s colors under that class name. Here we’ll call the class funky. Simply make sure to define an override color for all colors should change:

.funky {
  --bg: hotpink;
  --text-color: white;
  --link-color: #B793E6;
  --link-hover: #3532A7;
}

Fallbacks for Older Browsers

Support for CSS custom properties is pretty good, but you’ll most likely want to include fallbacks for users that are on older browsers.

Let’s say that we have an element that should have a linear-gradient background with colors defined as custom properties. It’s as simple as providing hard-coded colors first, and older browsers will ignore the version that they don’t understand:

background: linear-gradient(to right, #FFFB85, #5A3662); /* our fallback */
background: linear-gradient(to right, var(--top-grad1), var(--top-grad2));

Toggling Our Theme

We only need a very minimal amount of JavaScript to add an even listener on a element that acts as the toggle button between the two themes.

Here the toggle button has the toggle-theme class and we use document.querySelector to get a reference to that element:

let toggle = document.querySelector('.toggle-theme');

toggle.addEventListener('click', function(e) {
  e.preventDefault();

  if (document.body.classList.contains('funky')) {
    // Turning the theme off:
    document.body.classList.remove('funky');
    // Reverse logic on the button text, so that users can turn
    // the theme back on:
    toggle.innerText = '🤡 Turn theme on';
  } else {
    document.body.classList.add('funky');
    toggle.innerText = 'Turn theme off';
  }
});

This does the trick to toggle between the two themes. We can do better however and also add/remove an item to localStorage at the same time so that our theme gets applied automatically when the page loads:

let toggle = document.querySelector('.toggle-theme');

// Turn the theme of if the 'funky' key exists in localStorage
if (localStorage.getItem('funky')) {
  document.body.classList.add('funky');
  toggle.innerText = 'Turn theme off';
}

toggle.addEventListener('click', function(e) {
  e.preventDefault();

  if (document.body.classList.contains('funky')) {
    document.body.classList.remove('funky');
    toggle.innerText = '🤡 Turn theme on';
    localStorage.removeItem('funky');
  } else {
    document.body.classList.add('funky');
    toggle.innerText = 'Turn theme off';
    localStorage.setItem('funky', true);
  }
});
✖ Clear

🕵 Search Results

🔎 Searching...