Pico CSS is a classless (or almost classless and very minimal) CSS framework for building simple content driven sites.
i.e. Bootstrap if it was made my Linux's suckless.
Pico CSS does have a built-in dark mode theme or scheme, and it uses the settings from your web browser by default.
Firefox Themes
Those on Firefox may expect their OS dark mode to inform the browser dark mode setting... This is not always the case. Your browser theme may also need to be set.
Although Pico's documentation does explain the dark mode scheme, it's not super forth-coming with how to allow the user to dynamically change it using JavaScript.
After digging though their examples and discussion #381 on their Github. It looks like there's a small JavaScript file provided with a dropdown element (which also respects the browsers default choice), and even a JS one-liner (that does not respect the default scheme).
The Pico CSS website itself uses this somewhat hidden theme-switcher.js
code plus a dependency on "theme-toggles" from toggles.dev.
But, I wanted something with a bit more functionality but with fewer dependencies...
Pico CSS Emoji Theme Toggle
I modified their theme-switcher.js
to include a toggle function, and used the CSS colour variable --pico-contrast
to style a bank-and-white (uncoloured?) emoji known as "Black Sun with Rays" or U+2600
.
No need to toggle the SVG/image sprites when you can use CSS vars to colour an emoji.
In your sites' navigation, or where ever you'd like the dark mode setting, use the following in your HTML:
<a href="#" data-theme-switcher="toggle" title="Toggle Theme" style="color: var(--pico-contrast); font-size: 1.5em;">☀</a>
Then for the actual theme switcher JavaScript in theme-switcher.js
:
// https://benhoskins.dev/pico-css-theme-toggle/
const themeSwitcher = {
// Config
_scheme: "auto",
buttonsTarget: "a[data-theme-switcher]",
buttonAttribute: "data-theme-switcher",
rootAttribute: "data-theme",
localStorageKey: "picoPreferredColorScheme",
// Init
init() {
this.scheme = this.schemeFromLocalStorage;
this.initSwitchers();
},
// Get color scheme from local storage
get schemeFromLocalStorage() {
return window.localStorage?.getItem(this.localStorageKey) ?? this._scheme;
},
// Preferred color scheme
get preferredColorScheme() {
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
},
// Init switchers
initSwitchers() {
const buttons = document.querySelectorAll(this.buttonsTarget);
buttons.forEach((button) => {
button.addEventListener(
"click",
(event) => {
event.preventDefault();
// Set scheme
this.scheme = button.getAttribute(this.buttonAttribute);
},
false
);
});
},
// Set scheme
set scheme(scheme) {
if (scheme == "auto") {
this._scheme = this.preferredColorScheme;
}
else if (scheme == "toggle") {
this._scheme = document.documentElement.getAttribute('data-theme') === 'light' ? 'dark' : 'light';
}
else if (scheme == "dark" || scheme == "light") {
this._scheme = scheme;
}
this.applyScheme();
this.schemeToLocalStorage();
},
// Get scheme
get scheme() {
return this._scheme;
},
// Apply scheme
applyScheme() {
document.querySelector("html")?.setAttribute(this.rootAttribute, this.scheme);
},
// Store scheme to local storage
schemeToLocalStorage() {
window.localStorage?.setItem(this.localStorageKey, this.scheme);
},
};
// Init
themeSwitcher.init();
This theme switcher code looks for the browser default setting first, then and uses the toggle link to change as wanted.
It sets a data attribute on the HTML element, and uses local storage instead of cookies to persist any toggle overrides across pages.
As with the original theme switcher JS, you can also use dedicated "light", "dark" and "auto" as well as the "toggle" option I use in the HTML.
Comments & Questions
Reply by email to send in your thoughts.
Comments may be featured here unless you say otherwise. You can encrypt emails with PGP too, learn more about my email replies here.
PGP: 9ba2c5570aec2933970053e7967775cb1020ef23