Back

Multiple Palettes

How to let your website have different appearances based on visitors’ preferences

I usually separate styling declarations into 2 parts:

So styles use SCSS preprocessors ($variable) for all their values so that their are hardcoded in the resulting stylesheet - but the ones that are available to the palette which are CSS custom properties (var(--variable)) forming an API to styling the website.

This article is about leveraging this API to create multiple palettes and let the user choose one according to his preferences.

Note that each palette has to cover both themes (dark and light).

Palette composition #

A palette is comprised of the following elements:

Available palettes #

PaletteColorFontLightDark
picosystem-ui / monospace-ui
ayu34 bright colorsInter / Open Sans
nord16 dimmed pastel colorsRubik / Inter / Source Code Pro
nakedblack and whitesystem-ui / monospace-ui
solarized16 colorsDejaVu or Cousine
gnome45 colorscantarell

Implementation #

  1. Include all the stylesheets in your pages with a unique identifer (#id).
  2. Place a toggler in the page findable with .palette class name (like as follow). This feature being only available for people who have JS enabled, make sure your toggler is hidden is this is not the case.
  3. Add the palette variable to your site’s parameters in the config file. It expects a list of available palettes, the default one being the first. If this varible is missing, the fallback palette is named default.
  4. Insert the following script to activate the toggler.
  5. Done! 🎉

file: layouts/partials/palette_toggler.html

1{{ with site.Params.palette }}
2  {{ if gt (len .) 1 }}
3  <span class="palette" title="{{ i18n "palette_toggle" | default "Change color" }}">
4    {{ partial "icon" "palette" }}
5  </span>
6  {{ end }}
7{{ end }}

file: assets/scripts/togglePalette.js

 1// Retreive the palette choices
 2{{ $default := "default" }}
 3{{ $palettes := slice $default }}
 4{{ with site.Params.palette }}
 5  {{ $palettes = . }}
 6  {{ $default = index $palettes 0 }}
 7{{ end }}
 8
 9// Enable a specific palette
10function enablePalette(targetPalette) {
11  let currentPalette = document.documentElement.getAttribute("data-palette");
12  if (currentPalette !== targetPalette) {
13    let targetStyleSheet = document.getElementById(targetPalette);
14    let currentStyleSheet = document.getElementById(currentPalette);
15    targetStyleSheet && targetStyleSheet.removeAttribute("disabled");
16    currentStyleSheet && currentStyleSheet.setAttribute("disabled", true);
17    document.documentElement.setAttribute("data-palette", targetPalette);
18    window.localStorage && window.localStorage.setItem("palette", targetPalette);
19  }
20  let targetPaletteFancy = targetPalette.charAt(0).toUpperCase() + targetPalette.slice(1);
21  const message = '🎨 ' + targetPaletteFancy + ' {{ i18n "palette_on" | default "palette enabled"}}';
22  console.log(message);
23}
24
25// Switch from one palette to the next one
26function togglePalette() {
27  const palettes = ['{{ delimit $palettes "', '" }}'];
28  let currentPalette = document.documentElement.getAttribute("data-palette");
29  let currentIndex = palettes.indexOf(currentPalette);
30  let targetIndex = ++currentIndex % palettes.length;
31  let targetPalette = palettes[targetIndex];
32  enablePalette(targetPalette);
33}
34
35// Set inital Palette based on user's preferences
36function initPalette(adminPref) {
37  // When visitors doesn't have JS, palette feature is unavailable so let's no clutter the DOM unnecessarily
38  // With JS we force palette substitution and the attribute must not be left empty
39  document.documentElement.setAttribute("data-palette", adminPref);
40  const userPref = window.localStorage && window.localStorage.getItem("palette");
41  const targetPalette = !!userPref ? userPref : adminPref;
42  enablePalette(targetPalette);
43  document.addEventListener("DOMContentLoaded", event => {
44    const toggle = document.querySelector(".palette");
45    toggle.addEventListener("click", togglePalette, false);
46  });
47}
48
49// Initialize Palette
50initPalette("{{ $default }}");

Even more personalization #

If you want to provide the visitors with a supplementary level of customization, you can use further implement a variation of the primary/accent color with a color picker like:

That’s it for today!

Metadata
PublicationApril 28, 2022
Last editMay 30, 2022
SourcesView source
LicenseCreative CommonsAttribution - Some rights reserved
ContributeSuggest change
Comments