Skip to content

Modus-Logo-Long-BlackCreated with Sketch.

  • Services
  • Work
  • Blog
  • Resources

    OUR RESOURCES

    Innovation Podcast

    Explore transformative innovation with industry leaders.

    Guides & Playbooks

    Implement leading digital innovation with our strategic guides.

    Practical guide to building an effective AI strategy
  • Who we are

    Our story

    Learn about our values, vision, and commitment to client success.

    Open Source

    Discover how we contribute to and benefit from the global open source ecosystem.

    Careers

    Join our dynamic team and shape the future of digital transformation.

    How we built our unique culture
  • Let's talk
  • EN
  • FR

Operating systems and browsers have been learning new accessibility tricks capable of improving our screen-dependant lives. One of the most popular features, dark mode, helps our eyes adapt to low-light environments.


NEW RESEARCH: LEARN HOW DECISION-MAKERS ARE PRIORITIZING DIGITAL INITIATIVES IN 2024.

Get Report


Switching between dark to light modes is an incredibly useful feature for airplane pilots, commuters, and other road warriors. While the aesthetics are beautiful, the ability to adapt to ambient lighting can also be mission-critical. However, is it enough to replace the color scheme?

Switching Color Schemes

With the advent of CSS custom properties, dark and light profiles became a matter of setting and replacing variables.

A working example of setting a light color scheme for light-first applications could look like the following:

      :root {
        --background: white;
        --color: #2b2b2b;
      }
 
      body {
        background-color: var(--background);
        color: var(--color);
      }
 
      .darko {
        --background: #2b2b2b;
        --color: white;
      }

To override the theme to a dark profile, we’ll need to set a custom CSS rule to a top-level DOM element. It’s just a simple as setting a new class on the body element.

Some operating systems and browsers let users set the default appearance profile. A powerful new media query can help us identify those settings and let us automatically override the color profile.

      @media (prefers-color-scheme: dark) {
        :root {
          --background: #2b2b2b;
          --color: white;
        }
      }

With a beautifully crafted profile-switching app, we are almost ready to provide a rich, low-contrast user interface. However, media such as images can disrupt the experience.

Dark Mode for Images

A fully featured appearance mode switching should include images as well. One such approach can be using the background-image property.

#screenshot {
        background-image: url(settings-light.png);
      }
 
      @media (prefers-color-scheme: dark) {
        #screenshot {
          background-image: url(settings-dark.png);
        }
      }

The background-image property works excellent, but there are shortcomings related to responsiveness and automatic aspect ratio management. Using Img tags cannot be controlled by CSS, but can JavaScript be aware of the native appearance profile?

JavaScript has an interface for working with media queries. We can use it to obtain ad-hoc information or to listen for changes.

Let’s start by using the right image for our predefined lighting mode.

<script>
      const screenshotEl = document.getElementById('screenshot');
      const matchDark = window.matchMedia('(prefers-color-scheme: dark)');
 
      const setScreenshot = isDark =>
        (screenshotEl.src = `settings-${isDark ? 'dark' : 'light'}.png`);
 
      setScreenshot(matchDark.matches);
    </script>

Now that we are showing the right image, we want to let it react to changes in native settings.

      matchDark.addListener(e => {
        setScreenshot(e.matches);
      });

This listener attaches to the watchMedia API and resets the screenshot on every change.

Dark Mode Images Without JavaScript

While JavaScript offers infinite flexibility, staying within HTML and CSS will always yield more optimal performance. An ancient proverb clearly states: Thou shalt not witnesseth Javascript instead CSS or HTML.

The tag is great for responsive images. We are dealing with responsiveness in this case as our app responds to the user’s settings. Setting it up is straightforward.

<noscript> 
    <picture>
      <source srcset="settings-dark.png" media="(prefers-color-scheme: dark)" />
      <source srcset="settings-light.png" media="(prefers-color-scheme: light), (prefers-color-scheme: no-preference)" />
      <img id="screenshot" src="settings-light.png" />
    </picture>
</noscript>

Finally, we can produce a fully optimized profile-switching UI that ships with the color scheme we want and chooses the media that fits well with our environment.

Automatic Image Filtering

Having dedicated light and dark image files is sustainable for smaller-scope projects like landing pages. Some web apps may not have the luxury to have two versions of images. In that case, even a simple grayscale filter can help reduce brightness.

      @media (prefers-color-scheme: dark) {
        :root {
          --image-filter: grayscale(50%);
        }
 
        img:not([src*=".svg"]) {
          filter: var(--image-filter);
        }
      }

Grayscale filtering is a quick fix for controlling the light intensity in dark mode profiles. We only recommend it when it’s difficult to control images in a web application.

Users deserve the luxury of brightness profile selection. It doesn’t take significant effort to provide such feature since all the hard work is already in your users’ browsers.

The entire code is available for you on CodeSandbox. Please share this article if you think it could be helpful to your network.

Need efficient and scalable software solutions? Learn more about our software development expertise.

Posted in Application Development
Share this

Grgur Grisogono

Grgur Grisogono is a software architect at Modus Create, specializing in JavaScript performance, React JS, and Sencha frameworks. He helped clients ranging from Fortune 100 to major governments and startups successfully release enterprise and consumer-facing web applications. He has also organized three tech conferences and co-authored Ext JS in Action SE. If Grgur's posts were helpful, maybe his 16 years of experience could help your project too.
Follow

Related Posts

  • How to Use Image Placeholders in React Native
    How To Use Placeholder Images in React Native

    I’ve been working with React Native for over a year now. And one thing that…

  • How to Use Image Placeholders in React Native
    How To Use Placeholder Images in React Native

    I’ve been working with React Native for over a year now. And one thing that…

Want more insights to fuel your innovation efforts?

Sign up to receive our monthly newsletter and exclusive content about digital transformation and product development.

What we do

Our services
AI and data
Product development
Design and UX
Modernization
Platform and MLOps
Developer experience
Security

Our partners
Atlassian
AWS
GitHub
Other partners

Who we are

Our story
Careers
Open source

Our work

Our case studies

Our resources

Blog
Innovation podcast
Guides & playbooks

Connect with us

Get monthly insights on AI adoption

© 2025 Modus Create, LLC

Privacy PolicySitemap
Scroll To Top
  • Services
  • Work
  • Blog
  • Resources
    • Innovation Podcast
    • Guides & Playbooks
  • Who we are
    • Our story
    • Careers
  • Let’s talk
  • EN
  • FR