Why you should and how you could implement the dark mode

Posted on 14. November 2020

What is the dark mode

The dark mode, also called night mode, is a special color schema which uses light-colored text on dark backgrounds. The opposite of dark mode is the light mode which is or was the de facto default schema.

michilehr-de-dark-light-mode-comparison

One of the first websites to offer an optional dark mode was Discord in 2015. Microsoft and Apple added a dark mode for Windows 10 and macOS Mojave in late 2018. In September 2019, the amount of Discord users on the light mode was under 5 percent1.

Why you should implement the dark mode

There are more benefits of the dark mode than you think. It is not just a nice styling of the user interface, but also has effects on the human body and the power consumption of newer devices.

Effects on the human body

The effects of dark mode on visual fatigue and acuity can be enormous.

A study2 found that participants had a significantly higher visual acuity for the dark mode than the light mode. They were able to complete significantly more rows on the visual acuity test chart without errors for the dark mode.

Also, the visual fatigue of the participants was significantly lower for the dark mode than the light mode.

The participants also had a clear overall preference for the dark mode over the light mode which matches the preference of the Discord users. So maybe we should implement dark mode first?

However, the preference shifted towards the light mode for situations with even more environmental light.

Power consumption

The benefits of lower power consumption does not apply to all devices. Since all of the pixels in a LED display are illuminated by one LED backlight, these displays cannot benefit of a dark mode. The exception is the OLED display technology where each pixel provides its own illumination. An extreme test by appleinsider.com3 has shown that an OLED display used with dark mode can save up to 60 percentage battery over 3 hours.

Current devices with an OLED display for example

  • Google Pixel 4 / 5
  • Apple iPhone 12 / Mini / Pro / 12 Pro Max
  • ASUS ZenBook Pro UX581
  • HP Spectre x360 14
  • many more...

All these effects will not make a big difference unless more and more apps and websites will have implemented a dark mode - especially those we use more often. So it is up to us developers, designers and project managers to drive the dark mode forward.

How you could implement dark mode

There is more than one way to implement a dark mode color schema for your website. Let's get through some fundamental stuff and put everything together later.

System preference

A user can select his preferred color schema in the system settings of his operating system. This setting can be read by all modern browsers4, and we can query this setting in CSS via a media query.

/* user prefers dark mode */
@media (prefers-color-scheme: dark) {
    body {
        color: #f0f8ff;
        background-color: #363636;
    }
}

/* user prefers light mode */
@media (prefers-color-scheme: light) {
    body {
        color: #363636;
        background-color: #f0f8ff;
    }
}
Images on dark mode

A very bright image on a dark background can be annoying for its viewer. So why not decrease the brightness of the images with the CSS filter? The contrast ratio may be also important.

/* user prefers dark mode */
@media (prefers-color-scheme: dark) {
    img {
        filter: brightness(.9) contrast(1.1);
    }
}

/* user prefers light mode */
@media (prefers-color-scheme: light) {
    img {
        filter: brightness(1) contrast(1);
    }
}

Here is an example comparison between dark and light mode with an image with the above settings.

michilehr-de-dark-light-mode-example-images

If you were presenting photos on your website for which the colors and edit were important, maybe it will not be a good idea to alter its brightness

Listen to change events

Like other media query change events, you can subscribe to a change in the preferred system color schema via JavaScript.

This change can be triggered by the user or automatically by the operating system based on the time or illumination detection for example.

const prefersColorSchemaDarkMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
    prefersColorSchemaDarkMediaQuery.addListener((e) => {
    const darkModeActive = e.matches;
    // do something when dark mode has changed
});
Add a manual switch

When a user is not able to use a modern browser, or she wants to switch to the opposite mode without opening the system preferences every time, a manual switch should be implemented. This is useful when a user for example prefers the dark mode but is
in an environment with more light. The user can switch to the light mode, so she can interact with the user interface in a better way.

This can be implemented with a generic dark mode class which gets attached to the body element.

/* default light mode */ 
body,
body.colorSchemaLight {
    color: #363636;
    background-color: #f0f8ff;
}

/* class for dark mode */
body.colorSchemaDark {
    color: #f0f8ff;
    background-color: #363636;
}

When a user switches the mode manually, this setting should be saved in either a cookie or the local storage for example. Now it is your choice which setting should have a higher priority. I would suggest that the manual preference should have a higher priority than the system preference because this was chosen by the user intentionally.

Putting all together

For the complete implementation strategy of the CSS, you must decide which way is better depending on your target group. Semantically, I would prefer the usage of CSS variables. Also this would be much easier to implement. But since some older browsers do not support CSS variables4, I will also show you a way which is also good to maintain with the help of SCSS.

CSS version with variables
:root,
:root .colorSchemaLight {
  --background-color: #fff;
  --text-color: #202020;
}

body .colorSchemaDark
{
  --background-color: #202020;
  --text-color: #fff;
}

/* 
  We must copy the above code because 
  media queries cannot be combined
  with selectors
*/
@media (prefers-color-scheme: dark)
{
  :root {
    --background-color: #202020;
    --text-color: #fff;
  }
}

You can now use the colors as followed:

body {
  background: var(--background-color);
  color: var(--text-color);
}

Full Demo on CodePen

SCSS version
// define color schemas
$colorSchemas: (
  light: (
    background: #fff,
    text: #202020,
  ),
  dark: (
    background: #1f1f1f,
    text: #bfbfbf,
  ),
);

/// get color by schema from map
///
/// @param {string} $colorName
///   Color name from $colorSchemas
/// @return {string} hex color by colorName.
@function getColorForSchema($colorName) {

  $colorSchema: map-get($colorSchemas, $colorSchemaName);
  $color: map-get($colorSchema, $colorName);

  @return $color;
}

/// mixnin to fill CSS content
/// 
/// @param {bool} $isBody
///   If mixin is used in body element
@mixin useColorSchema($isBody: false) {

  $colorSchemaName: 'light' !global;

  @if $isBody {
    &,
    &.colorSchemaLight {
      @content;
    }
  } @else {
    &,
    .colorSchemaLight & {
      @content;
    }
  }

  $colorSchemaName: 'dark' !global;

  @media (prefers-color-scheme: 'dark') {
    @content;
  }

  @if $isBody {
    &.colorSchemaDark {
      @content;
    }
  } @else {
    .colorSchemaDark & {
      @content;
    }
  }

  $colorSchemaName: null !global;
}

You can use the mixin useColorSchema by this:

body {
  @include useColorSchema(true) {
    background-color: getColorForSchema('background');
    color: getColorForSchema('text');
  }
}

Which generates following CSS:

body, body.colorSchemaLight {
  background-color: #fff;
  color: #202020;
}
@media (prefers-color-scheme: dark) {
  body {
    background-color: #1f1f1f;
    color: #bfbfbf;
  }
}
body.colorSchemaDark {
  background-color: #1f1f1f;
  color: #bfbfbf;
}

The negative impact of the implementation via SCSS and a mixin is also that more CSS code will be generated.

Full Demo on CodePen

Pro tip

If you were using the modern frontend framework React, you can use the use-dark-mode component which handles the logic, so you will only have to implement the (S)CSS part.


  1. Kevin Wilson. 2019. https://blog.discord.com/light-theme-redeemed-c541b7ab13e9
  2. Gerd Bruder, Austin Erickson, Kangsoo Kim. 2019. Effects of Dark Mode on Visual Fatigue and Acuity in Optical See-Through Head-Mounted Displays
  3. Neil Hughes. 2017. https://appleinsider.com/articles/17/11/10/extreme-test-shows-oled-iphone-x-with-dark-mode-saves-nearly-60-battery-over-3-hours
  4. https://caniuse.com/?search=prefers-color-scheme
Made with ♥️ and Gatsby © 2024