/ / / / / / / / / / / / / / / /
this is the second version of the guide, and the code itself. the first version still works fine, i just figured i could do it better now.
this guide is intented for people with little to no knowledge of javascript, but preferably decent knowledge of html/css. i did my best to keep things simple, though.
keep in mind this still may not be the best way to do this, i'm not really a js expert myself.
/ / / / / / / / / / / / / / / /
you will need a div with the id themes-container, and buttons inside it:
<div id="themes-container"> <button id="theme-default">light (default)</button> <button id="theme-dark">dark</button> </div>
each button has an id, which will be the name of the class the script gives to the html element. it doesn't need to be in this theme-name format, except theme-default! i did it that way so it's less likely to be an id you already used somewhere.
again, do not change the id for theme-default! if you do, you'll also have to find and replace all instances of it in the script (ctrl+h).
the text inside the button can be anything you want, it doesn't matter.
important: the buttons cannot have any classes! the way the script works, it removes all classes on the buttons, and adds selected to the active one. you will have to style them using "#themes-container button"!
if you want to add more themes, all you have to do is add more buttons! just remember to use a unique id, and you're all good!
well, of course you'll also have to write the css for the new theme, but more on that later.
you also need to actually add the script. unless you just want this on a single page (or, even then), i recommend having the script in a separate file. link it before the closing body tag on every page you want themes on, like this:
/ / / / / / / / / / / / / / / /
note that the default theme doesn't have a class!
basically, write the css for your website as you normally would, then add the other, non-default themes near the end (after all your normal css, but before any media queries, i think)
how the themes work is that you style the theme class and its children after the normal css (the default theme) and override it when the theme class is active.
remember to also style the selected class! it can even be as simple as changing the font weight, like on this page, just don't forget to do it.
here's a simple example:
note that the element being given the theme classes is the html element (aka the root of the document), not body. use ".theme body" to style the body, and etc...
why did i make the html element have the classes and not body? honestly i just thought the code would be a little clearer that way... i guess it doesn't really make a big difference.
anyway, you can also overwrite css variables in your themes, like i do on my website:
this one has only the theme class because the root element is what you usually define variables for! technically, you could change them for a child too, though... but again, i think this is clearer?
like i said in the html section, you'll need to link your script at the bottom of the body, on every page you want themes on!
make a new file like "themes.js" or whatever else you wanna call it (just remember to link the right filename!), then just copy-paste the script from here:
// test local storage (from MDN) function storageAvailable(type) { let storage; try { storage = window[type]; const x = "__storage_test__"; storage.setItem(x, x); storage.removeItem(x); return true; } catch (e) { return ( e instanceof DOMException && e.name === "QuotaExceededError" && // acknowledge QuotaExceededError only if there's something already stored storage && storage.length !== 0 ); } } // no local storage info (console) if (!storageAvailable("localStorage")) { console.log("local storage not available, themes will not save!") } // define theme list variable const themeList = document.querySelectorAll("#themes-container button"); // set default theme button class to selected document.getElementById("theme-default").className = "selected"; // theme loader function (called on page load) function getTheme() { //variables const theme = localStorage.getItem("theme"), matchingButton = document.getElementById(theme); // unselect all buttons for (const themeButton of themeList) { themeButton.className = "" } // set active button to selected (if it exists*) // *in case the theme has been removed from the list since being set, etc if (matchingButton !== null) { matchingButton.className = "selected"; } // default theme -> no class, any other theme -> class is theme name if (theme == "theme-default") { document.documentElement.className = "" } else { document.documentElement.className = theme } } // theme changer function (called on button press) function changeTheme(element, theme) { // unselect all buttons for (const themeButton of themeList) { themeButton.className = "" } // set active button to selected element.className = "selected"; // default theme -> no class, any other theme -> class is theme name if (theme == "theme-default") { document.documentElement.className = "" } else { document.documentElement.className = theme } // set local storage item if (storageAvailable("localStorage")) { localStorage.setItem("theme", theme) } } // check if theme exists in local storage if (localStorage.getItem("theme")) { getTheme() } else { localStorage.setItem("theme", "theme-default") } // add event listeners for (const element of themeList) { element.addEventListener("click", function() { let elementId = this.getAttribute("id"); // call theme changer function changeTheme(this, elementId); }) }
i will try to explain the code as well in case you'd like to understand it!
first is a function that tests if storage is available, which i just copied from MDN...
then that function is called to check if local storage works, and if not, it'll say so in the console (if you know some js, you could change this to have some kind of warning appear on the page itself. i didn't want to complicate things, though)
these next two bits are just defining the variable that contains the list of the theme buttons, and giving the one with the id theme-default the class of selected.
next is the function that gets the theme from local storage. it removes the classes from all the theme buttons, gives the selected class to the active theme's button (if it exists, because otherwise removing one can break the script), and sets the root element's class to nothing if the theme is theme-default or the theme name otherwise.
now the last function, the one that's called when you press one of the theme buttons. it's similar to the previous one; it removes classes from the theme buttons and gives the selected class to the active theme's button, sets the root element's class to nothing if the theme is theme-default or the theme name otherwise, and then sets the local storage item to the theme name.
then, if "theme" exists in local storage, getTheme is called, and otherwise "theme" in local storage is set to theme-default.
and finally, adding the event listeners for every button in the themeList variable (which is all the buttons in the themes-container id div), so that when you click the button, changeTheme is called with the current element and its id as the parameters.
did any of this make sense? is it helpful? i don't know, but it's there for you! and for me, if i ever forget what this code does, i guess...
/ / / / / / / / / / / / / / / /