DEV Community

Cover image for Dark Mode - Unmistified! 🐱‍👤
Akhil Arjun
Akhil Arjun

Posted on

Dark Mode - Unmistified! 🐱‍👤

Disclaimer!
This is going to be a long post. I will try and assimilate all the resources and information I have on a proper dark mode implementation on your website.


CSS Filter Hack!

I have explained this setup in my previous post. And I should repeat, it is only a hack and not a proper flawless dark theme implementation.

JS Implementation

So now we know, how to make an awesome dark mode using CSS. For the above-mentioned implementation, the javascript idea is very straightforward.

const html = document.getElementsByTagName('html')[0];
const toggleTheme = (theme) => {
    html.dataset.theme = theme;
}
Enter fullscreen mode Exit fullscreen mode

And now all you have to do is call the toggleTheme() method from UI with dark and light values respectively.

Native Dark/ Light mode ?

Am I telling you, that you can detect system preference for light/ dark mode from CSS or js?

Absolutely I am!


Heck Yeah

Say hello to the sassy new Media Queries!

<script>
  // If `prefers-color-scheme` is not supported, fall back to light mode.
  // In this case, light.css will be downloaded with `highest` priority.
  if (window.matchMedia('(prefers-color-scheme: dark)').media === 'not all') {
    document.documentElement.style.display = 'none';
    document.head.insertAdjacentHTML(
        'beforeend',
        '<link rel="stylesheet" href="/light.css" onload="document.documentElement.style.display = \'\'">'
    );
  }
</script>
<!--
  Conditionally either load the light or the dark stylesheet. The matching file
  will be downloaded with `highest`, the non-matching file with `lowest`
  priority. If the browser doesn't support `prefers-color-scheme`, the media
  query is unknown and the files are downloaded with `lowest` priority (but
  above I already force `highest` priority for my default light experience).
-->
<link rel="stylesheet" href="/dark.css" media="(prefers-color-scheme: dark)">
<link rel="stylesheet" href="/light.css" media="(prefers-color-scheme: light)">
<!-- The main stylesheet -->
<link rel="stylesheet" href="/style.css">
Enter fullscreen mode Exit fullscreen mode

What the above code does is, it checks for any preference set by the user regarding light mode/ dark mode. And according to this preference, the browser downloads appropriate CSS files.

One thing to note is even though the system preference would be for the dark mode, the browser does download the other CSS as well but with the lowest priority.

Now, what if we want to do all of it in javascript?

  • dynamically check what is the preferred color scheme
  • override theme in the application if the user wants to
  • remember that decision by the user using localStorage

I would say totally doable!


No way

Enter Javascript magic!

Self-advertisement Warning Rolling In 😎😁

This is a library I built using vanilla js which does exactly what we have been discussing. And reducing your workload to just two lines

Include the js file

<script src="https://cdn.jsdelivr.net/gh/akhilarjun/tinylibs@latest/themejs/theme.min.js" onload="setupThemeIcon()"></script>
Enter fullscreen mode Exit fullscreen mode

And an image with id theme-selector and onclick function as switchTheme(this)

<img src="./sun.svg" 
    data-light-src="./sun.svg" 
    data-dark-src="./moon.svg"
    alt="light theme" 
    id="theme-selector"
    onclick="switchTheme(this)">
Enter fullscreen mode Exit fullscreen mode



data-light-src and data-dark-src if provided will be used to swap between icons while changing the theme attribute of Html tag.

Mic Drop Time 🎤

The library will even auto-detect the system preference change and switch themes between dark and light.

And we will try doing this using chrome dev tools.


Result

That's it for today guys. Cheers! Its Coffee time.
My days are fueled with coffees and only coffees. So I know, you know what we all should do 🤞


Buy Me A Coffee


Well done

References

Top comments (13)

Collapse
 
tateronaut profile image
tate shepherd • Edited

I don't know why, but I couldn't get your js to work exactly how you have it for the first basic "JS Implementation" in conjunction with the css in your last post . I had to do some minor tweaks. Maybe I just wasnt implmementing yours right, but this is what I ended up doing.

// app.js
const onClickHandler = () => {
  document.documentElement.setAttribute('data-theme','dark');
}

with my css being

/* style.css */
[data-theme='dark'] {
  filter: invert(1) hue-rotate(180deg);
}

(EDIT: Thought it'd be helpful to include my html button)

<button onclick="toggleTheme('dark')">Dark</button>

I could of course update with other themes and pass a variable to my JS function.

Cool posts though! I still need to work through your "Native mode" section

Collapse
 
akhilarjun profile image
Akhil Arjun

Oh, could you tell me more? Of where it went wrong. I would be happy to help or even better if there is a bug in my code. I could fix it up 😎

Collapse
 
tateronaut profile image
tate shepherd

Sure. Here is a pen of my implementation of your code, I'm probably just messing up the syntax. codepen.io/tateshep/pen/YzqzKxb

Here is one of what I did to make it work how I'd expect
codepen.io/tateshep/pen/dyMbdZE

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️ • Edited
<body dark>

body {
   --lightness: .8;
}
body[dark] {
   --lightness: .2;
}
p {
   color: hsla(200, 60%, calc(1 - var(--lightness)));
   /* etc. */
}

🤷

Collapse
 
akhilarjun profile image
Akhil Arjun

Only if more people would use and understand hsla 😍😍

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

I know right? It's the easiest way to write colours, yet everybody still uses hex-codes for some reason... Worst part about it is, many people apparently can't even read/write hex codes and just copy-paste them around.

Thread Thread
 
tateronaut profile image
tate shepherd

I don't understand hsla, and am definitely guilty of copy pasting hex codes. You've inspired me to check it out! I'd love a more logical way of doing colors than hex codes

Thread Thread
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

Nice! I sure hope it makes your life easier :D

Collapse
 
livetvchannels profile image
Trieu.iv

it worked! but not available on firefox :)

Collapse
 
akhilarjun profile image
Akhil Arjun

Yeah the support is sketchy. But it should support all modern browser versions.

caniuse.com/#feat=prefers-color-sc...

Collapse
 
ridbay profile image
ridbay❁

How can this be implemented in ReactJS

Collapse
 
akhilarjun profile image
Akhil Arjun

Since it is a native js plugin. I don't think it should in any way interfere with the React application lifecycle. Include theme.js in your index.html and make sure to call the switchTheme() method from your component's onClick handle.
I am not a React expert, but I am sure this should work. Let me know if it doesn't I will give it a try myself ✌

Collapse
 
isarisariver profile image
Marian

Great series, will try this on my app, too.
I came here to read more about dark mode, but I stayed for the Arnold GIF.