How-to

The code behind this CSS theming

The foundation of this way of theming is CSS. Using HTML dataset to make it persistent. And use Javascript to set and switch between themes.

1. Set Theme constant in the HTML body dataset


The theme is executed by a dataset in the body tag and changed by Javascript

<body data-theme="dodger">
/* And the Javascript line that changes this */

document.body.dataset.theme = localStorage.theme;

2. Use CSS variables to make it more DRY


Setting CSS variables and use them instead of #900 etc, the colors will be dynamic. Using hsl() this will be even easier to make a consistent theme - just edit the last percent to make it darker or lighter.

[data-theme='default'] {
--bg: hsl(255, 99%, 98%);
--dark: hsl(255, 99%, 95%);
--medium: hsl(255, 99%, 78%);
--lite: hsl(255, 99%, 94%);
--hover: hsl(255, 99%, 88%);
--select: hsl(255, 99%, 93%);
--black:  hsl(255, 0%, 20%);
--white:  hsl(255, 30%, 99%);
--text_header: hsl(255, 70%, 50%);
--icn_header: hsl(255, 70%, 50%);
--icn: hsl(255, 70%, 50%);
--formbg: hsl(255, 99%, 97%);
--stop: hsl(0, 100%, 30%);
--ok: hsl(120,100%,30%);
}

[data-theme=indigo] {
--bg: hsl(255, 99%, 97%);
--dark: hsl(255, 99%, 65%);
--medium: hsl(255, 99%, 75%);
--darklite: hsl(255, 99%, 85%);
--lite: hsl(255, 99%, 97%);
--hover: hsl(255, 99%, 90%);
--select: hsl(255, 99%, 93%);
--black: hsl(0, 0%, 20%);
--darkgray: hsl(0, 0%, 40%);
--white:  hsl(255, 30%, 99%);
--text_header: hsl(255, 70%, 98%);
--icn_header: hsl(255, 70%, 98%);
--icn: hsl(255, 70%, 50%);
--formbg: hsl(255, 99%, 97%);
--stop: hsl(0, 100%, 50%);
--ok: hsl(120,100%,50%);
}

[data-theme=dodger] {
--bg: hsl(210, 99%, 97%);
--dark: hsl(210, 99%, 65%);
--medium: hsl(210, 99%, 75%);
--darklite: hsl(210, 99%, 85%);
--lite: hsl(210, 99%, 97%);
--hover: hsl(210, 99%, 90%);
--select: hsl(210, 99%, 93%);
--black: hsl(0, 0%, 20%);
--darkgray: hsl(0, 0%, 40%);
--white:  hsl(210, 30%, 99%);
--text_header: hsl(210, 70%, 98%);
--icn_header: hsl(210, 70%, 98%);
--icn: hsl(210, 70%, 50%);
--formbg: hsl(210, 99%, 97%);
--stop: hsl(0, 100%, 30%);
--ok: hsl(120,100%,30%);
}

[data-theme=barbie] {
--bg: hsl(300, 99%, 98%);
--dark: hsl(300, 99%, 65%);
--medium: hsl(300, 99%, 75%);
--darklite: hsl(300, 99%, 85%);
--lite: hsl(300, 99%, 97%);
--hover: hsl(300, 99%, 90%);
--select: hsl(300, 99%, 93%);
--black: hsl(0, 0%, 20%);
--white:  hsl(300, 30%, 99%);
--darkgray: hsl(0, 0%, 40%);
--text_header: hsl(255, 70%, 98%);
--icn_header: hsl(255, 70%, 98%);
--icn: hsl(300, 70%, 50%);
--formbg: hsl(300, 99%, 97%);
--stop: hsl(0, 100%, 30%);
--ok: hsl(120,100%,30%);
}

[data-theme=classic] {
--bg: hsl(250, 20%, 97%);
--dark: hsl(250, 20%, 65%);
--medium: hsl(250, 20%, 75%);
--darklite: hsl(250, 20%, 85%);
--lite: hsl(250, 20%, 95%);
--hover: hsl(250, 20%, 80%);
--select: hsl(250, 20%, 80%);
--black: hsl(0, 0%, 20%);
--white:  hsl(250, 30%, 99%);
--darkgray: hsl(0, 0%, 40%);
--text_header: hsl(250, 20%, 98%);
--icn_header: hsl(250, 20%, 98%);
--icn: hsl(250, 20%, 50%);
--formbg: hsl(250, 99%, 97%);
--stop: hsl(0, 100%, 30%);
--ok: hsl(120,100%,30%);
}

[data-theme=snowflake] {
--bg: hsl(250, 20%, 97%);
--dark: hsl(250, 20%, 97%);
--medium: hsl(250, 20%, 75%);
--darklite: hsl(250, 20%, 85%);
--lite: hsl(250, 20%, 95%);
--hover: hsl(250, 20%, 90%);
--select: hsl(250, 20%, 90%);
--black: hsl(0, 0%, 20%);
--white:  hsl(250, 30%, 99%);
--darkgray: hsl(0, 0%, 40%);
--text_header: hsl(0, 0%, 20%);
--icn_header: hsl(0, 0%, 20%);
--icn: hsl(0, 0%, 20%);
--formbg: hsl(250, 99%, 97%);
--stop: hsl(0, 100%, 30%);
--ok: hsl(120,100%,30%);
}

3. Set, store and display theme using Javascript


Javascript is used to initialize (change body dataset and check for current theme) as well as used to set desired theme and store this into localStorage.

// set to default if theme is empty
window.addEventListener('load', (event) => {
if (localStorage.theme === "undefined") {
set_theme('default')
}
document.body.dataset.theme = localStorage.theme;
});

function set_theme(name) {
document.body.dataset.theme = name;
localStorage.setItem("theme", name);
}

function set_prefs(theme,name){
set_theme(theme)
document.getElementById('theme').innerHTML = name
document.getElementById('details').removeAttribute('open')
}

// store from accordion
let themes = document.getElementById("select").querySelectorAll("li")
themes.forEach(function(theme) {
theme.addEventListener("click", function() {
document.getElementById('theme').dataset.theme = this.dataset.theme
set_prefs(this.dataset.theme, this.innerHTML)
})
});

// prepare the accordion when loading page 
function init() {
for (let item of themes) {
if (item.dataset.theme === localStorage.theme){
  set_prefs(item.dataset.theme,item.innerHTML)
}
}
}
init()

By using svg icons as "Symbols" without color you can change the color dynamically

4. Use SVG Symbol technique to affect svg icons

<!--<?xml version="1.0" encoding="UTF-8"?>-->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none">

<symbol id="hamburger" viewBox="0 0 32 32">
<path fill="none" d="M0 0h32v32h-32v-32z"></path>
<path d="M10.377 12.116h12.389v1.418h-12.389v-1.418z"></path>
<path d="M10.377 15.424h12.389v1.418h-12.389v-1.418z"></path>
<path d="M10.377 18.731h12.389v1.417h-12.389v-1.417z"></path>
<path fill="#f1f1f1" d="M19.495 11.176h0.026v0.053h-0.026v-0.053z"></path>
</symbol>

<symbol id="hub" viewBox="0 0 56 56">
<path d="M20.88,20.83h3.417c0.158,0,0.285,0.127,0.285,0.285v3.417c0,0.158-0.127,0.285-0.285,0.285H20.88
c-0.157,0-0.284-0.127-0.284-0.285v-3.417C20.596,20.957,20.723,20.83,20.88,20.83z" />
<path d="M26.29,20.83h3.418c0.156,0,0.284,0.127,0.284,0.285v3.417c0,0.158-0.128,0.285-0.284,0.285H26.29
c-0.156,0-0.284-0.127-0.284-0.285v-3.417C26.006,20.957,26.134,20.83,26.29,20.83z" />
<path d="M31.701,20.83h3.417c0.157,0,0.285,0.127,0.285,0.285v3.417c0,0.158-0.128,0.285-0.285,0.285h-3.417
c-0.157,0-0.285-0.127-0.285-0.285v-3.417C31.416,20.957,31.544,20.83,31.701,20.83z" />
<path d="M20.88,26.24h3.417c0.158,0,0.285,0.127,0.285,0.285v3.417c0,0.158-0.127,0.285-0.285,0.285H20.88
c-0.157,0-0.284-0.127-0.284-0.285v-3.417C20.596,26.368,20.723,26.24,20.88,26.24z" />
<path d="M26.29,26.24h3.418c0.156,0,0.284,0.127,0.284,0.285v3.417c0,0.158-0.128,0.285-0.284,0.285H26.29
c-0.156,0-0.284-0.127-0.284-0.285v-3.417C26.006,26.368,26.134,26.24,26.29,26.24z" />
<path d="M31.701,26.24h3.417c0.157,0,0.285,0.127,0.285,0.285v3.417c0,0.158-0.128,0.285-0.285,0.285h-3.417
c-0.157,0-0.285-0.127-0.285-0.285v-3.417C31.416,26.368,31.544,26.24,31.701,26.24z" />
<path d="M20.88,31.65h3.417c0.158,0,0.285,0.128,0.285,0.285v3.417c0,0.157-0.127,0.285-0.285,0.285H20.88
c-0.157,0-0.284-0.128-0.284-0.285v-3.417C20.596,31.778,20.723,31.65,20.88,31.65z" />
<path d="M26.29,31.65h3.418c0.156,0,0.284,0.128,0.284,0.285v3.417c0,0.157-0.128,0.285-0.284,0.285H26.29
c-0.156,0-0.284-0.128-0.284-0.285v-3.417C26.006,31.778,26.134,31.65,26.29,31.65z" />
<path d="M31.701,31.65h3.417c0.157,0,0.285,0.128,0.285,0.285v3.417c0,0.157-0.128,0.285-0.285,0.285h-3.417
c-0.157,0-0.285-0.128-0.285-0.285v-3.417C31.416,31.778,31.544,31.65,31.701,31.65z" />
</symbol>

</svg>

Using CSS you can set the css color variable to the svg symbols.

5. Style the svg using CSS stroke and fill

#icn_hamburger svg:hover {
stroke: var(--stop);
fill: var(--stop);
}