In this tutorial, we’ll discuss how to implement different color schemes on a website using CSS variables and one line of vanilla JavaScript. First, we’ll implement a simple light/dark mode toggle switch. Then we’ll expand on that to implement as many themes as we’d like; light mode, dark mode, 90’s neon mode, you name it!
We’ll also use media queries to display dark or light mode depending on a user’s preferences, and local storage to remember which of our color schemes they’ve selected.
Light/Dark Mode Toggle Switch Demo
Let’s take a look at the demo for a light/dark mode toggle switch. We’ll be building this first, then expanding on it.
1. How to Create a Dark Mode Toggle
HTML
First, we’ll initialise two buttons to allow us control light and dark mode.
<div class="toggle-container"> <button class="theme-btn light" title="Light mode"> <!--sun icon--> </button> <button class="theme-btn dark" title="Dark mode"> <!--moon icon--> </button> </div>
I used these weather icons from Envato Elements for the sun and moon to represent light and dark themes, but you can replace them with whatever content you prefer. I also set the title
attribute to provide context for screen readers.
CSS
Most of the work with our toggle implementation is done using CSS. We can style the buttons to achieve the rounded icon effect:
.theme-btn { width: 3em; height: 3em; padding: 0.5em; border-radius: 50%; cursor: pointer; border: none; background-color: transparent; } .theme-btn img { height: 100%; width: 100%; object-fit: cover; }
We define our theme colors using CSS custom properties.
“Custom properties [...] contain specific values to be reused throughout a document. They are set using custom property notation (e.g.,
--main-color: black;
) and are accessed using thevar()
function (e.g.,color: var(--main-color);
)” - MDN
Custom properties are usually defined inside the :root
pseudo-class, which allows us to target the <html>
element tag. In this example, we defined the variables for a default, light and dark theme for the :root
using class names.
:root, :root.light { --bg-color: #fff; --text-color: #123; } :root.dark { --bg-color: #121212; --text-color: #45ADFE; }
Now we’ll assign our custom properties to other elements–this is what allows the colors to change depending on the :root
class. We can assign colors to the body
like this:
body { background-color: var(--bg-color); color: var(--text-color); }
The body tag returns the selected variable color depending on the class assigned to the :root
.
JavaScript
At this point we can use JavaScript to determine the class for the :root
tag and, as promised, we’ll only need one line:
const setTheme = theme => document.documentElement.className = theme;
The setTheme
function sets the root
element’s class to the parameter theme
.
We can pass this function to our buttons so the updated HTML looks like this:
<div class="toggle-container"> <button class="theme-btn light" onclick="setTheme('light')" title="Light mode"> <!--sun icon--> </button> <button class="theme-btn dark" onclick="setTheme('dark')" title="Dark mode"> <!--moon icon--> </button> </div>
Clicking the light button sets the HTML class to light
and clicking the dark button sets the HTML class to dark
.
Here’s what happens to our HTML element depending on the button clicked:
And the style for the body tag looks like this:
With this, we’ve implemented everything we need to switch between a light and dark theme!
2. Handling Styling Based on Color Theme
Thanks to this implementation, we can choose to style elements differently based on which class name the HTML element has. In our demo, we only display one button at a time so we can hide the other button depending on the chosen class. Here’s what the CSS looks like:
.theme-btn.light { display: none; } .dark .theme-btn.light { display: block; background-color: #fff; } .dark .theme-btn.dark { display: none; }
With this, we show the light button and hide the dark button when the parent element has a class dark
.
3. More Custom Properties
CSS custom properties are not just limited to colors, we can change everything from font size to background images. Here’s a demo where we change the font style and background image using the toggle switch.
Images used: Young woman with curly hair smiling and Millennial group of friends lighting sparklers at night.
We only need to update the CSS so it looks like:
:root, :root.light { --bg-color: #d6e8f5; --text-color: #0a1c29; --bg-url: url(//image-url); --font-family: 'Fredoka One', cursive; } :root.dark { --bg-color: #0a1c29; --text-color: #45ADFE; --bg-url: url(//image-url); --font-family: 'Alfa Slab One', cursive; } body { background-image: var(--bg-url); background-size: cover; color: var(--text-color); font-family: var(--font-family); }
4. Multiple Color Schemes
Now that we’ve implemented the light/dark mode toggle, we can go ahead to expand on that to create as many color schemes as we’d like.
For this method, we’ve created a dropdown that allows you select 6 different themes for your page. Take a look at the demo:
HTML
In this example, we use a select
element to create the dropdown and pass the themes into the select as options. The values of the options are what we’ll be passing to the HTML element as classes.
<select name="theme-select" id="theme-select"> <option value="light">Light</option> <option value="dark">Dark</option> <option value="blue">Blue</option> <option value="pink">Pink</option> <option value="space">Space</option> <option value="nyan">Nyan</option> </select>
CSS
We’ll create our :root
variables for the different themes using class names.
:root, :root.light { --bg-color: #fff; --text-color: #123; } :root.dark { --bg-color: #121212; --text-color: #696d7d; } :root.blue { --bg-color: #05396B; --text-color: #E7F1FE; } :root.pink { --bg-color: #ffcad4; --text-color: #e75480; } :root.space { --bg-color: #000; --text-color: #f2bd16; --bg-url: url(//space); --font-family: 'Press Start 2P', cursive; } :root.nyan { --bg-color: #013367; --text-color: #fff; --bg-url: url(//nyan); --font-family: 'Comic Neue', cursive; }
We can also style the select tag to use the variables instead of default styling:
select { padding: 0.25rem 0.75rem; font-size: 1.25rem; font-family: inherit; background-color: var(--bg-color); color: var(--text-color); border-radius: 0.25rem; }
Then our body style looks like this:
body { margin: 0; background-color: var(--bg-color); background-image: var(--bg-url); color: var(--text-color); font-family: var(--font-family, "Open Sans", sans-serif); }
Note: we can also pass fallback values into CSS variables, so setting the property font-family: var(--font-family, "Open Sans", sans-serif
allows the browser to set the font-family property as "Open Sans", sans-serif
if the CSS variable --font-family
is undefined.
JavaScript
Finally, we update our JavaScript to detect when an option has been chosen from the select element.
const setTheme = theme => document.documentElement.className = theme; document.getElementById('theme-select').addEventListener('change', function() { setTheme(this.value); });
We target the select element and pass the selected value in setTheme
as the root class.
That’s all the JavaScript we need and we can go ahead to have as many themes as we’d like by including more HTML options and :root styles in the CSS.
5. Setting Theme According to User Preferences
We can also decide whether to set a light or a dark mode based on the user system’s preferences. We can detect a user’s preferred color scheme by using the prefers-color-scheme
media query .
“The
prefers-color-scheme
CSS media feature is used to detect if the user has requested a light or dark color theme.” - MDN
@media (prefers-color-scheme: dark) { :root { --bg-color: #121212; --text-color: #45ADFE; } }
In the media query, we set our default :root
variables to the colors for our dark mode if the user’s system is set to a dark theme.
6. Store User Choice in Local Storage
Another feature is storing a user’s selected theme in local storage so the page takes the chosen theme by default every time they visit. We can modify our setTheme
function to store the selected option in local storage.
const setTheme = (theme) => { document.documentElement.className = theme; localStorage.setItem('theme', theme); }
To load the saved theme when the page loads, we can create a getTheme
function that gets the theme item from localStorage and call the function whenever the script is loaded:
const getTheme = () => { const theme = localStorage.getItem('theme'); theme && setTheme(theme); } getTheme();
Conclusion
To summarize, we can create a theme selector by:
- Setting theme colors for the
:root
using CSS variables - Using JavaScript to change the root class.
- Calling the function in the corresponding HTML element.
With this, we’ve created a fully functional theme selector that saves user options and takes their preferences into consideration.
No comments:
Post a Comment