Your browser doesn’t support some of the latest CSS features used to build this site.

Read more about my usage of new CSS features.

A demo of using CSS custom properties to switch colour schemes on a website.

Theme switcher

As soon as I saw demos of CSS custom properties I wanted to use them to build a theme switcher to change the entire colour scheme on a website — with potential accessibility uses in the future for high contrast themes, and also font resizing.

A simple example

Hit the button to switch the blue colours of this website to a pink theme:

A more realistic example

A high contrast theme is a practical use of theme switching — changing the colours to be higher contrast can help visually impaired users and aid accessibility. You tend to see contrast theme switchers on websites that strive for accessibility, for example the Manchester City Council’s accessibility page where I got the colours for my high contrast theme.

Hit the toggle button to switch the colour scheme of this website to high contrast mode:


Dive into some code

Set up

A simplified version of the code for this demo:

// Get DOM elements to change
const html = document.querySelectorAll('html')[0]
const buttons = document.getElementsByTagName('button')

// Get and cache current styles
let styles = window.getComputedStyle(document.querySelector('html'))
const brandColorA = styles.getPropertyValue('--c-brand-color-a')
const brandColorADark = styles.getPropertyValue('--c-brand-color-a--dark')
const contrastBase = styles.getPropertyValue('--c-contrast-base')
const contrastColor = styles.getPropertyValue('--c-contrast-color')
const bodyBgColor = styles.getPropertyValue('--c-body-bg')
const bodyTextColor = styles.getPropertyValue('--c-body-color')

// Theme logic variables
let contrastOn = false

// Bind events to buttons
for (let i = 0; i < buttons.length; ++i) {
  buttons[i].addEventListener('click', switchColour)
}

The colour switching functionality

The general idea here is to detect if the theme has already been applied using contrastOn and if not, update the custom properties on the :root element to have the new colour values. When switching back, change them to the properties we cached above. Doing this at the root level allows the changes to cascade throughout the document.


var switchColour = function () {
  if (!contrastOn) {
    html.style.setProperty('--c-brand-color-a', contrastBase)
    html.style.setProperty('--c-brand-color-a--dark', contrastBase)
    html.style.setProperty('--c-body-bg', contrastBase)
    html.style.setProperty('--c-body-color', contrastColor)
  } else {
    html.style.setProperty('--c-brand-color-a', brandColorA)
    html.style.setProperty('--c-brand-color-a--dark', brandColorADark)
    html.style.setProperty('--c-body-bg', bodyBgColor)
    html.style.setProperty('--c-body-color', bodyTextColor)
  }

  contrastOn = !contrastOn
}

Using el.style.setProperty allows you to change the CSS custom property dynamically with JavaScript. Yes you could manipulate colours with JS before, but now we can manipulate custom properties (essentially variables) changing one property can cascade throughout the whole page if needed.

A screenshot of Chrome dev tools showing the changed custom properties for the high contrast theme A screenshot of Chrome dev tools showing the changed custom properties for the new theme
The updated custom properties in Chrome dev tools

Caveats

Does your browser support these features?

  • CSS custom properties

Although your browser may support some of the experimental features needed for this demo, I recommend viewing it in Chrome Canary or Firefox Nightly for the best experience.

As it always seems, there is the caveat that CSS custom properties aren’t widely supported yet, which makes the point of using them for accessibility enhancements moot. This also means that if you’re viewing this experiment in a non-supporting browser, I’m afraid it won’t appear to do anything. Below are some screenshots instead.

A screenshot of this website showing the new theme
The updated website theme
A screenshot of this website showing the high contrast theme
The high contrast theme

TL;DR

Using CSS custom properties and manipulating them via JavaScript I have made a proof-of-concept theme switcher.

For this to be extended I may store the value in a cookie in order to sustain the theme change across the entire website. — I have done this now.

Another use case for this is to build a font resizer — again another aid for accessibility.

As always, the code for my website project is publicly available, so have a little look if you want to implement something like this on your projects, and let me know how you get on!