Dark Mode CSS Only
This theme switcher functions without using JavaScript. However you do need some JS to make it persistent across multiple pages and user visits. Typically this is done by setting a localStorage value when the theme is changed and then checking that value on every page load.
Prerequisites
There are now multiple ways to set up dark themes. This will use the color-scheme property in the :root element along with the light-dark() function for setting colours.
For example:
:root {
color-scheme: light dark;
--text: light-dark(#222, #ccc);
}
The HTML element
The HTML can be done different ways. Here we’ll use the <select> element. The default value will be system and because there’s no CSS set for this value it won’t do anything. So the user’s system settings will be used, either light or dark, until they choose something else.
<select name="theme" id="theme">
<option value="system">system</option>
<option value="dark">dark</option>
<option value="light">light</option>
</select>
The CSS
This sets the :root element color-scheme value based on a descendant selector #theme [value="dark"]:checked. The ID #theme is our <select> element. And [value="dark"]:checked is an attribute selector within #theme.
:root:has(#theme [value="dark"]:checked) {
color-scheme: dark;
}
:root:has(#theme [value="light"]:checked) {
color-scheme: light;
}
To make the transitions smooth:
body {
transition: all 0.4s ease-out;
}
The Javascript
The JavaScript is fairly simple:
// grab the select element
const select = document.querySelector('select');
// Listen for a change on the select element
// Record the change to localStorage
select.addEventListener('change', () => {
localStorage.setItem('theme', select.value);
})
// Create a function to check the localStorage setting
// Set the select element to that value
function checkTheme () {
const theme = localStorage.getItem('theme');
select.value = theme;
}
// Run the function when the page loads
checkTheme();