Implementing Dark Mode in Web Design for Better User Experience
Step-by-step tutorial on adding light and dark modes to websites for starters
Introduction
Hey there, fellow web designers and developers! Have you ever found yourself squinting at your screen late at night, wishing your website had a sleek dark mode option? Well, you're in luck because today we're going to explore how to implement this user-friendly feature and take your web design game to the next level!
First things first, what is dark mode? Dark mode is a color scheme that uses a dark background with light text and UI elements. It's become increasingly popular in recent years because it can reduce eye strain, especially in low-light environments, and it can also help conserve battery life on devices with OLED or AMOLED displays.
Now, why would you want to implement dark mode in your web design? Well, aside from the benefits mentioned above, it can also provide a sleek and modern look to your website, and it can enhance the overall user experience by giving your users the option to choose their preferred color scheme.
So, let's get started!
CSS Variables:
So you know how variables in programming languages like JavaScript or Python let you store values and reuse them throughout your code? CSS has a similar concept called custom properties, or CSS variables, and they're pretty awesome!
Imagine you have a color code that you want to use in multiple places in your CSS file. Instead of repeating that long hexadecimal value over and over again, you can store it in a variable and simply refer to that variable wherever you need that color. Neat, right?
Here's how it works:
You create a variable by giving it a name that starts with two dashes, like --primary-color
. Then, you assign it a value, like a color code or a number. For example:
--primary-color: #ff6347; /* Tomato color */
Now, whenever you want to use that color in your CSS, instead of typing out the hex code every single time, you can simply refer to the variable name using the var()
function.
body {
background-color: var(--primary-color); /* This will be tomato red */
}
Isn't that awesome? It's like a little shortcut that makes your CSS code cleaner and easier to maintain.
But wait, there's more! You can define these variables at different scopes. If you declare a variable inside the :root
selector, it becomes a global variable that you can use anywhere in your stylesheet. However, if you define it inside a specific selector, like body
or header
, it becomes a local variable that only works within that scope.
:root {
--global-color: #000; /* This is a global variable */
}
body {
--local-color: #fff; /* This is a local variable */
color: var(--local-color); /* This will be white */
background-color: var(--global-color); /* This will be black */
}
And here's the really cool part: if you redefine a global variable with a new value inside a local scope, it overrides the global value within that scope! It's like a little CSS variable rebellion happening right there in your code.
:root {
--color: #000; /* Global variable is black */
}
header {
--color: #ff6347; /* Local variable overrides global and is tomato red */
color: var(--color); /* This will be tomato red */
}
body {
color: var(--color); /* This will be black, using the global variable */
}
So, in summary, CSS variables are like little placeholders that you can use to store and reuse values throughout your stylesheets. They make your code more organized, easier to maintain, and even allow for some cool scope-related shenanigans
Alright, enough chit-chat, let's get to the good stuff! ๐ป
How to Implement Dark Mode
Step 1: HTML Markup
In this example, we have a straightforward HTML document showcasing the basic structure of a web page. Despite its simplicity, this document serves as the canvas for implementing dark mode using CSS and JavaScript, transforming the website into a sleek, eye-friendly experience through code.
<!DOCTYPE html>
<html>
<head>
<title>Dark Mode Example</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<button id="darkModeToggle">Toggle Dark Mode</button>
<h1>Welcome to my website!</h1>
<p>This is an example of a website with dark mode implemented.</p>
<script src="app.js"></script>
</body>
</html>
Step 2: Setup your CSS
Now that we've got a solid understanding of how CSS variables work, it's time to put that knowledge to use and set up a dark mode for our website. By using these nifty little variables, we can keep our code nice and organized while making it super easy to manage and maintain. Sounds good, right?
Here's how we're going to do it:
/* Light Mode */
:root {
--background-color: #ffffff; /* white background */
--text-color: #333333; /* dark gray text */
--accent-color: #007bff; /* blue accent color */
}
First up, we're defining our light mode color scheme using CSS variables inside the :root
selector. This means these variables have a global scope, so we can use them anywhere in our stylesheets. We've set up variables for the background color, text color, and an accent color (like for links or buttons).
Next, let's create a new set of variables for our dark mode:
/* Dark Mode */
:root.dark-mode {
--background-color: #333333; /* dark gray background */
--text-color: #ffffff; /* white text */
--accent-color: #007bff; /* same blue accent color */
}
Here, we're targeting the :root
selector again, but this time with the .dark-mode
class attached. This allows us to redefine our variables with new values that will be used whenever we apply that .dark-mode
class to our HTML.
Now, we can use these variables to style our website elements:
body {
background-color: var(--background-color);
color: var(--text-color);
}
a {
color: var(--accent-color);
}
See how we're using var(--variable-name)
to insert the current value of each variable? When our site is in light mode (no .dark-mode
class), the body
will have a white background and dark gray text, and the links will be blue. But when we toggle the dark mode by adding the .dark-mode
class, the body
will have a dark gray background and white text, while the links stay blue.
Pretty slick, right? With just a few lines of CSS and some clever use of variables, we've set up a system for switching between light and dark modes on our website. And the best part? If we ever want to change the color scheme, we only need to update the variable values, and the changes will automatically propagate throughout our styles. Talk about efficient coding!
Step 3: JavaScript for toggling dark mode
Now that we've set up our CSS variables and defined our color schemes for light and dark modes, it's time to bring in a bit of JavaScript magic to make that toggle button work! With just a few lines of code, we can add an event listener to our toggle button that will add or remove the .dark-mode
class from our HTML element. This will update the variable values throughout our CSS, effectively switching between light and dark modes.
Let's break it down step-by-step:
First up, we have these two lines:
const darkModeToggle = document.getElementById('darkModeToggle');
const rootElement = document.documentElement;
Here, we're creating two variables: darkModeToggle
and rootElement
. The darkModeToggle
variable is storing a reference to the toggle button on our webpage. We're getting this button using document.getElementById('darkModeToggle')
, which looks for an element with the ID darkModeToggle
on the page.
The rootElement
variable is storing a reference to the root HTML element of our webpage, which is the <html>
tag. We're getting this using document.documentElement
.
Next, we have this line:
const prefersDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;
This line is checking if the user's operating system preferences are set to dark mode. It's using the window.matchMedia
function, which is a built-in JavaScript function that allows us to check if the user's device matches certain conditions, like preferring dark mode or having a specific screen resolution.
If the user's device prefers dark mode, the prefersDarkMode
variable will be set to true
. If not, it will be set to false
.
After that, we have this code block:
if (prefersDarkMode) {
rootElement.classList.add('dark-mode');
}
This is an if
statement, which is a way to run some code only if a certain condition is met. In this case, if prefersDarkMode
is true
(meaning the user's device prefers dark mode), then the code inside the curly braces { }
will run.
The code inside the curly braces is rootElement.classList.add('dark-mode')
. This line is adding the class dark-mode
to the root HTML element (<html>
) of our webpage. Remember, the rootElement
variable is storing a reference to this <html>
tag.
By adding the dark-mode
class to the <html>
element, we're telling our CSS styles to use the dark mode color scheme that we defined earlier using CSS variables.
Finally, we have this code:
darkModeToggle.addEventListener('click', () => {
rootElement.classList.toggle('dark-mode');
});
This line is adding an event listener to our toggle button. An event listener is a way to run some code when a specific event happens, like a button being clicked or a key being pressed.
In this case, we're adding an event listener that listens for a click
event on the darkModeToggle
button. When the user clicks the button, the code inside the curly braces { }
will run.
The code inside the curly braces is rootElement.classList.toggle('dark-mode')
. This line is toggling (adding or removing) the dark-mode
class on the root HTML element (<html>
). If the dark-mode
class is already present, it will be removed. If it's not present, it will be added.
By toggling the dark-mode
class on and off the <html>
element, we're telling our CSS styles to switch between the light mode and dark mode color schemes that we defined earlier using CSS variables.
So, in summary, this JavaScript code is:
Getting references to the toggle button and the root HTML element.
Checking if the user's device prefers dark mode.
If the user prefers dark mode, adding the
dark-mode
class to the root HTML element to set the initial mode.Adding an event listener to the toggle button. When the user clicks it, the
dark-mode
class is toggled (added or removed) on the root HTML element, switching between light and dark modes.
And there you have it, folks! With our CSS variables, some strategic HTML markup, and a sprinkle of JavaScript magic, we've successfully implemented a sleek dark mode toggle for our website. Experience the smooth transition between light and dark color schemes by clicking the toggle below:
Pretty cool, right? Who knew a few lines of code could make such a difference in the user experience? Now, our visitors can choose their preferred color scheme and enjoy a more comfortable browsing experience, whether it's during the day or late at night.
Let's notice what's going on behind the scenes here :
Our dark-mode
class gets added to the body of our document when the toggle is clicked on, which prompts all the values of the custom CSS properties used all over our webpage to get overridden with the new values in the .dark-mode
class. Clicking on it again removes this class, which results in our initial global variables taking effect again.
Now let's take a peek at Hashnode's own implementation of their dark mode:
Notice it's basically the same concept, but they're simply adding the .dark-mode
class to the <html>
element instead of the <body>
. Pretty cool, right?
Best Practices for Dark Mode Implementation
Now that you've mastered the basics of implementing a dark mode toggle, let's take a look at some best practices to ensure a smooth and user-friendly experience. First and foremost, it's crucial to maintain proper color contrast between text and background elements in both light and dark modes. This not only enhances readability but also caters to users with vision impairments, ensuring accessibility compliance.
When selecting your color schemes, consider using tools like WebAIM's color contrast checker or browser developer tools to verify that your text and background combinations meet the recommended contrast ratios. Additionally, pay special attention to interactive elements like buttons, links, and form fields, ensuring they remain easily distinguishable and usable in both modes.
Another best practice is to provide a consistent experience across your entire website or application. Ensure that all components, including third-party libraries or embedded content, respond appropriately to the chosen color scheme. This may involve customizing or overriding styles for external resources to maintain a cohesive look and feel.
Furthermore, remember to test your dark mode implementation across various devices and screen sizes. OLED and AMOLED displays may render colors differently, and you'll want to ensure that your design looks great on a wide range of devices. Consider implementing responsive design principles to adapt your color schemes and layouts accordingly.
Lastly, consider offering users the ability to choose their preferred color scheme upon their initial visit or provide a persistent setting that remembers their choice across sessions. This personalized approach not only enhances user experience but also demonstrates your commitment to accessibility and inclusivity.
By following these best practices, you'll not only create a visually appealing and user-friendly dark mode implementation but also showcase your attention to detail and commitment to delivering an exceptional user experience.
Conclusion
Congratulations on finishing this tutorial! ๐ As an additional note, there is an alternative method that I discovered a while ago. In that tutorial, the instructor wanted to give website users the option to choose between three color modes: light, dark, and blue mode. To achieve this, they created separate stylesheets for each theme, manually edited the styles in each stylesheet, and then used JavaScript to dynamically swap the stylesheet link based on the user's choice.
However, this method resulted in a noticeable 1-2 second delay when switching between themes. This was because the browser had to download and apply the new stylesheet, which negatively affected the user experience. Using CSS variables, as we have done here, is generally a more efficient and user-friendly approach. However, you are free to experiment and find what works best for your specific use case.
If you found this tutorial helpful (which I'm sure you did ๐), have a question, or noticed an error or typo, please leave your feedback in the comment section below. Also, remember that someone out there may be struggling to implement a dark mode feature, so be sure to share this resource and follow me for more useful content like this.
If you're feeling generous (which I hope you are ๐) or want to support me, you can make me smile by buying me a cup (or a thousand cups) of coffee using the link below:
Buy Me A Coffee ๐
Happy coding, and may the dark mode be with you! โจ