How we shipped dark mode in just 2 days š
Iāve been thinking, talking and experimenting with dark mode here in Slido literally for a few years now. So when someone finally asked me: āWe need dark mode, ASAP. Can you help?ā, I knew I was ready.
Now, Iād like to give this superpower to you.
ā¦and to be completely frank with you, we really did get dark mode to production in just 2 days, but we also reserved additional 8 days in advance, to get rid of the tech debt that weāve introduced in those 2 days.
The technical solution
First, letās figure out, how to define and maintain 2 color palettes at the same time. There are multiple ways but the most reasonable one, and the one that you should go for, is native CSS Variables.
CSS Variables
With modern CSS, thanks to CSS Variables, you can define colors as variables and change them in real time.
So how do we take advantage of them?
First, we define 2 color palettes ā one for light, and one for dark mode, on the :root
element like so:
:root {
--bg-color: #FFFFFF; // background for light mode š
}.dark-mode {
--bg-color: #000000; // background for dark mode š
}
Then, we use these colors in our CSS/SCSS files:
body {
background: var(--bg-color); // the magic š
}
And finally, we toggle dark mode whenever necessary by adding dark-mode
class on the body
element.
if (isDarkModeEnabled) {
documeny.body.classList.add('dark-mode');
} ...
All of this is pretty simple (as most of the code should be), and here is an example of what it could look like:
IE11 + CSS Variables = š
A huge topic for us, when it came to dark mode, was IE11 support. For a long time, we were considering CSS variables to be the best option for color customisability, but IE11 with its non-existing support for CSS variables stood in the way.
Sure, nowdays you can polyfill them for IE11, for example, by using ponyfill or postcss-custom-properties, but in our experience, the implementation and maintenance cost for either of these just wasnāt worth it. Especially so, if we are talking about a browser, which we ultimately want to stop supporting.
We therefore decided to simply not support dark mode on IE11 (and to only display the default light mode on this prehistoric browser).
By the way, we werenāt the only ones to make such a decision. For example, StackOverflow went a bit further and dropped support for IE11 altogether because of the dark mode that they have introduced last year.
So the plan is to replace all colors in our CSS files with CSS variables. But in that case, IE11 wonāt know what color to display, right? Yeah, but to fix that, weāve used postcss-custom-properties, which generates fallbacks for IE11.
These fallbacks then look something like this:
background: #FFFFFF;
background: var(--white-1);
This way, IE is able to read the first line and ignore the other, while the rest of the browsers can take advantage of the CSS variable on the second line.
Alternative approaches
Even though CSS variables are superior to other approaches, letās mention other approaches that have popped up in our minds, as they might prove helpful to you.
- Generate multiple sets of CSS files out of your SCSS files (one for each color mode). ā With this approach, you will have no troubles with IE, but you will end up with 2 files, which could get quite big.
- Tailwind āIf youāve heard about or have been considering using Tailwind in your project, you should know that the support for dark mode has been added in version 2.0. However, it requires you to define the desired dark mode colors on each element, and can get quite verbose.
- āDark Mode Hack Fileā āThink of a single file that contains just the diff between light and dark mode, so that when this file is loaded, it transforms all light colors into dark ones.
Why do we mention this āhackā approach, you ask?
Hacking dark mode in 2 days
For business reasons, we needed to make the dark mode available as quickly as possible, and the āDark Mode Hack Fileā approach is essentially what enabled us to ship dark mode in 2 just days. Well that is cool, isnāt it?
Yeah, but among Slido developers, we often use the phrase āThere is nothing more permanent than a temporary solution.ā Therefore, we knew that we had to redo it properly right away or else it would be weighing us down.
Despite the āDark Mode Hack Fileā approach being ugly, it was a good stepping stone towards a proper solution ā it helped us understand the complexity of the project and weāve identified all the CSS rules that needed adjusting for dark mode.
Colors
When it comes to colors, here are some tips regarding 3 topics: Choosing them quickly, choosing them properly, and taking advantage of the situation and cleaning them up.
Creating dark palette quickly
If you are implementing dark mode on an existing project with a light palette already defined, chances are that you can just use a clever trick to switch color from light to its dark alternative.
In our case, the majority of the colors were just different shades of grey, defined in RGBA color space as black color with a variable alpha channel.
Generating the first iteration of our dark mode palette was as simple as switching the R, G and B channels from 0 to 255 and leaving the A (alpha) channel untouched.
Similar trick can be applied on colors in HSL (hue, saturation, lightness), by fiddling with the lightness channel.
Creating dark palette properly
In reality, switching 0
to 255
wonāt always do the trick. When doing things properly, you want consistency, cleanliness and simplicity.
Creating a proper palette is therefore all about creating a system.
In our case, the designers have created a palette that goes from black to white for each color, in the same number of steps. Each color got its name and each existing color was mapped to this palette.
Having enough colors in the palette is important so that designers always have enough colors to choose from. This way, the palette doesnāt become obsolete so quickly. Names are useful for making the communication between developers and designers easier.
The cleanup
An opportunity to dig deep into your CSS files and colors doesnāt come often. Therefore, if possible, take advantage of such a situation and try cleaning the styles up a bit.
One of the candidates for such clean-up would be the amount of different shades of a color, that should have been the same. (E.g. 3 different border colors in 3 different places.)
We tackled this problem by listing all the colors weāve been using in our codebase, grouping them by similarity and pinpointing them to a new color from our new color palette.
The result was a cleaner, more pleasant look.
Detecting light/dark mode
It might not seem obvious at first, but despite having just 2 color palettes, most applications are supporting 3 different modes:
- Automatic ā based on OS or browser
- Always light
- Always dark
In our case, we wanted to go easy on our users. We hid the āAutomaticā option and went for a toggle with 2 positions instead. By default, our application is in auto mode and the toggle simply displays which theme is active. But as soon as you touch it, you will forever (well, almost forever) be using that mode. Just for the sake of simplicity.
You can detect whether the userās browser/OS prefers a dark theme with:
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
// The user prefers dark mode š
}
ā¦and it is always nice to surprise your users with dark mode if they prefer it.
The result
Surprisingly, working on the dark mode was even more fun, than I originally anticipated!
It brought a lot of delight to our costumers, and I canāt wait until the pandemic is over, so that we can take advantage of dark mode in dark conference rooms, where we were previously blinding our participants with the original light theme.
And last but not least ā huge thanks for help goes to Adam Ciganik, Milos Lajtman, Michal Mikulasik, Maros Holly and Janka Kovacikova. š
Is there anything we missed? Let us know!