DEV Community

Ekaterina Vujasinović
Ekaterina Vujasinović

Posted on • Edited on

Dark Mode With One Line Of Code

Dark mode can be implemented with a single line of code. Let’s see how it's done and the benefits and drawbacks of this simple approach.

filter: invert(100%)

invert() function as the value of the filter property will take the number from 0 to 1 or percentages from 0% to 100% to invert the colors of the element and its children. Applying filter: invert(1) or filter: invert(100%) results in fully inverted colors.

You can use this single line of CSS to switch the color scheme from light to dark (or the other way around).

To invert the colors of the entire website, you need to apply filter: invert(100%) on the highest-level element of the DOM:



:root {
  filter: invert(100%);
}


Enter fullscreen mode Exit fullscreen mode

Applying filter with toggle button

To switch the theme, you need a toggle button and a class with dark mode styles to be toggled on the button click. Check the Codepen example below and click the button in the middle to change the color scheme:

The filter property inside the .dark-mode class is responsible for changing the colors.



/* this class will be toggled */
.dark-mode {
  filter: invert(100%)
}


Enter fullscreen mode Exit fullscreen mode

We must employ some basic JavaScript by targeting the document.documentElement inside the listener function. Then we can toggle the .dark-mode class on the top of the DOM hierarchy to apply the filter: invert(100%) sitewide.



let button = document.querySelector('.btn')

// press the button to toggle the .dark-mode class
button.addEventListener('click', () => {
document.documentElement.classList.toggle('dark-mode')
})

Enter fullscreen mode Exit fullscreen mode




The pros and cons of inverting all the pixels

The benefits of making your entire site switch from the light to the dark mode with filter: invert(100%) are obvious: it's a quick and dirty solution. And, like every quick solution, it also has some significant downfalls.

filter applied on the top of the DOM tree is going to cascade down and affect all the child elements. It’s going to invert all the colors. It results with the following list of problems (and let’s pretend that every bullet point ends with: “Additional code is necessary to fix this”):

  • Media like images and videos gets inverted, and it never looks good (but you probably still want to have the SVGs inverted).

All pixels are inverted, including the image
  • All dark box-shadows will become highlights.

  • If your website has colors other than black, white, or grayish nuances, you might be surprised by how bad some colors look inverted.


Light blue color becomes not-so-pretty brown color
  • Where there was once a sufficient contrast on the light background, things can change when color gets inverted and when it's against the dark background.


The contrast of the inverted color on the dark background is very low
  • Think about hover, focus, active, visited, and all other special element states. Do colors convey the state of the elements when inverted or is the color meaning lost? What about interactives?

  • Some advanced UI advice by Steve Schoger that adds to the point
    https://twitter.com/steveschoger/status/1151160261170126850

This list could go on and on, dealing with all kinds of usability and accessibility details that would be sorely missed when inverting the entire color scheme. The point is - you expected to implement the dark mode with a single line of code and spent the entire day writing CSS to fix all the problems.

To invert or not to invert?

The final verdict for filter: invert(100%) is: it is super-useful for making the details look good. You could use it to switch the colors of the entire site though if your site is very simple and monochromatic.

In all other cases, you should probably try some content-aware techniques instead. For example, here is the Dark Mode - The prefers-color-scheme Website Tutorial article (and its GitHub repository) I wrote on implementing the dark mode with prefers-color-scheme media-query, variables, and JavaScript.

Top comments (19)

Collapse
 
louislow profile image
Louis Low

This is to solve all that above problems with a little modification. Like you suggested, inverting the whole page would also be inverting the images which are not a complete solution. We can apply two steps to make it a nearly silver bullet.

Step #1: invert all elements

html {
  filter: invert(1) hue-rotate(180deg)
}
Enter fullscreen mode Exit fullscreen mode

Step #2: invert-back and restore image color

Invert and rotate the hue color to 180 degrees to revert and restore the image original color with this below.

img, picture, video {
  filter: invert(1) hue-rotate(180deg)
}
Enter fullscreen mode Exit fullscreen mode

Optional compensation for element that is stubborn.

[class="invert"] {
  filter: invert(1) hue-rotate(180deg)
}
Enter fullscreen mode Exit fullscreen mode
<div class="invert">
  ...
</div>
Enter fullscreen mode Exit fullscreen mode
Collapse
 
ekaterina_vu profile image
Ekaterina Vujasinović

Loouis, I partially agree with you - this is a great way to solve the inverted images problem. But, there is a whole list of problems to be solved separately when inverting all the pixels, not only images. E. g. if you just invert the colors of the complex UI, there is a great chance it won't look good and you'll need a lot of adjustments. So, yes, nearly silver bullet but only for very simple design.

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀

I was going to say that haha. Adjustment required. I should read all the comments first.

Collapse
 
druiznyc profile image
Daniel Ruiz

If you just use the :not() css selector you don't need the code above. This solves the issue and doesn't waste processor power on converting and unconverting images with the filter tag

.dark-mode :not(img):not(.inverted){ filter: invert(100%) }

Collapse
 
humayunkabir profile image
Humayun Kabir

I tried to resolve the issue according to both Loouis Low and Daniel Ruiz way. Both are great solutions. But facing problem with the background image. Any workaround, guys?

Collapse
 
robertotonino profile image
Roberto Tonino

That [class="invert"] scared me a little bit. Great solution though.

Collapse
 
louislow profile image
Louis Low

If don't want such cumbersome. Why not using a CSS framework. You can dynamically add dark mode to any element, it's easy. Read this article.

Collapse
 
ryanroat profile image
Ryan Roat

This was featured on the DesignCourse youtube channel (with attribution) - youtube.com/watch?v=qimopjP6YoM - and I used it on a project today.

I also had to wrap my head around serving the javascript toggle functionality on the client-side of my express app, but once I did that, it worked perfectly for my prototype! Thanks!

Collapse
 
malloc007 profile image
Ryota Murakami

I've never seen filter CSS property and invert(100%) value, how affect this.

I'm really glad about get read the post!
Thank you so much! 🤗

Collapse
 
ekaterina_vu profile image
Ekaterina Vujasinović

I'm glad it was helpful!😉

Collapse
 
ackvf profile image
Vítězslav Ackermann Ferko • Edited

This article is rubbish and promotes wrong techniques and the title is nothing but a clickbait.

It's important to note why this is a bad idea:

The eye perceives the lighter shades with much better contrast than the darker shades. Simply inverting changes the balance of the ratios!

Simply put: What you distinguish as multiple shades with good contrast when using lighter shades will look like a single color when using darker shades and therefore you will lose the UI elements.

This is basically the same image, but inverted. Notice the loss of detail when inverting White UI to Black UI.
light shades
dark shades
source: simandl.cz/stranky/fotky/kalibrace...

Collapse
 
roundxoutside profile image
Nikodem Domaracki

If anyone is interested, you can make yourself a quick "darkmode" switch button. Create bookmark and copy paste this code in url field:

javascript:(function() {document.getElementsByTagName("html")[0].style.filter = "invert(1) hue-rotate(180deg)";Array.from(document.getElementsByTagName("img"), e => e.style.filter = "invert(1) hue-rotate(180deg)");})();
Enter fullscreen mode Exit fullscreen mode
Collapse
 
shrihankp profile image
Shrihan • Edited

Since this approach has its downsides, I prefer Tailwind CSS Dark mode. I have used it on all web apps that require it, and I'm happy with it 😉

Edit: just realized this article is very old, but anyways...

Collapse
 
e5pe profile image
Esperanza Cutillas Rastoll • Edited

I tried this at codepen:

The mode changes if you press enter on the results view.

Great solution :)

Collapse
 
madeindjs profile image
Alexandre Rousseau • Edited

I tried to do this trick on my personal blog but I noticed some performaces issue on smartphone view when I scroll fast. So I go back to CSS specific rules and thes lags disapears.

Collapse
 
digvijaysingh profile image
Digvijay Singh

Amazing trick, the page looks even better. Saved me to write tons of CSS. Thanks.

Collapse
 
slimdestro profile image
D\sTro

I wish you would've posted this 1 year ago when I had to write big javascrip method just to achieve this feature 😆 nice post 👌