loading...
Cover image for Dark mode: the "best" way (IMO)

Dark mode: the "best" way (IMO)

timmingau profile image Tim Ming Updated on ・3 min read

This blog post provides you a quick TL;DR for the best way to implement dark mode into your website.

Difficulty: Beginner

So, did I mean by the best?

  • Browser support
  • Performance
  • Simplicity

In my opinion; though, there are supporting facts.

---- Let's jump right into it: ----

There are many ways to implement dark mode:

I'm specifically promoting the data-theme method. Click here if you can't bother about the others.

Why choose data-theme?:

  • amazing browser support.
  • lightweight.
  • clean code.

For other methods:

@media(prefers-color-scheme)

Use @media(prefers-color-scheme) if you're against legacy browsers. Here's why.

Seperate CSS files

Please, for the love of developers - don't use this method. Having seperate CSS files will negatively impact your webpage rendering speed. More CSS files means more HTTP Requests are sent to fetch your files, in which will consequently slow down the rendering process.

classList toggle

Well... if you're experienced, you probably heard of the classList.toggle method. Yeah, it works exactly the same as data-theme. Feel free to use it without guilt.

Code

Now that the explanation's done, let me show you an example.

Codepen Example

HTML

I used pug for my HTML, but incase you don't know what's going on:

<div id="container">
  <div id="theme-text">Hi, I'm light theme</div>
  <div id="theme-switch">Click me to change theme</div>
</div>

CSS

I used SCSS as my preprocessor; worry not, I didn't put any SCSS stuff in here. To access the attributes associated with the element, use square brackets. In this case, data-theme="dark" is to be accessed when its value is "dark".

:root{
  --color-bg:#faf7f0;
  --color-font:#363636;
}

body[data-theme="dark"]{
  --color-bg: #282930;
  --color-font: #b1b3bd;
}

body{
  background-color:var(--color-bg);
  color:var(--color-font);
  font-size:1.5rem;
  transition:.2s background-color,.2s color;
}

#container{
  display:flex;
  align-items: center;
  justify-content: center;
  flex-direction:column;
  margin-top:35vh;
}

#theme-switch{
  border:1px var(--color-font) solid;
  margin-top:1rem;
  padding:1rem;
  border-radius:1rem;
  user-select:none;
  cursor:pointer;
}

You will need to use variables if you want it clean. You can create variables to store any value, with the syntax:
--+name:value
Make sure you create them in :root to prevent scope problems.

JS

This is vanilla javascript. :) Noticed how I used the localStorage.setItem method. This works only for the client browser. If you want it to work for the same user on any client, check out SSP.

const themeText = document.getElementById("theme-text")
const themeSwitch = document.getElementById("theme-switch")
if (window.localStorage.getItem("theme") === "dark"){
  document.body.dataset.theme = "dark";
  themeText.innerHTML = "Hi, I'm dark theme";
}
themeSwitch.addEventListener("click",function(){
  if(document.body.dataset.theme !== "dark"){
    document.body.dataset.theme = "dark"
    themeText.innerHTML = "Hi, I'm dark theme"
    window.localStorage.setItem("theme","dark")
  }else{
    document.body.dataset.theme = "light"
    themeText.innerHTML = "Hi, I'm light theme"
    window.localStorage.setItem("theme","light")
  }
})

The data-theme attribute in body is accessed with dataset.theme in JS.

---------End---------

There you go! This is how you can easily add dark mode without any regrets. Though, remember that this is only a small part of the module - at least let me guide you for the design.

My design

Dark mode design examples

<3

Posted on by:

timmingau profile

Tim Ming

@timmingau

HS graduate | aspiring web dev+designer, seeking endlessly for optimizations.

Discussion

pic
Editor guide
 
;(function (window, document, undefined) {
    'use strict';
    if (!('localStorage' in window)) return;
    var nightMode = localStorage.getItem('gmtNightMode');
    if (nightMode) {
        document.documentElement.className += ' dark';
    }
const userPrefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
const userPrefersLight = window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches; 

if(userPrefersDark){
    document.documentElement.className += ' dark';
}
})(window, document); 
 

I am interesting to see (struggling to find working easy solution) where @media is used in first place and button is changing with it. When user don’t what dark theme he can always click button to revert, but my default prefers-Color-Scheme taking charge. Any advise.

 

The demo is not working on mobile

 

I'm so sorry! May I know which browser are you using?

 

Sorry, I should have mentioned it. Im using Brave on Android. But just tested with Chrome on Android and it works fine... Maybe it's just my browser?

I think that might be the case! Though brave on iOS works perfectly... Unfortunately I can't find a way to find support for other browsers... That was my bad!

 

forget about the 1 line js code bla bla bla to turn website into dark mode. using css variables is the best way 👍

 

Its good to squeeze in every drop of performance :)