Dark Mode with prefers-color-sheme Media Query

Posted

Dark Mode is all the range with desktop and mobile OS’es right now. Interestingly, modern browsers can detect the OS dark mode preference, and use a different set of CSS styles respectively for light or dark modes! Here’s how I updated My custom Grav theme.

Prefers-color-scheme

The dark mode styles lie in the media query as show below. For my implementation using Bulma, I only needed to override the following styles:

@media (prefers-color-scheme:dark) {
 body { background-image:linear-gradient(141deg,#112 0%, #223 20%,#445 100%) !important; color:#aad }
 img { opacity:0.8 }
 .box { background-color:#112; color:#aad }  
 .footer { background-color:#223; color:#aad }  
 .navbar, .navbar-dropdown, .navbar-menu  { background-color:#112 }
 .navbar-item, .navbar-link, .navbar-burger { color:#aad }
 .notices { background-color:#223 !important }
 .title, .panel-block { color:#ddf}
 .input { background-color:#334; color:#ddf; border-color:#209cee }
 .tabs a { color:#aad }
 .tabs a:hover { color:#ddf; border-bottom-color:#fff }
 .tag:not(body) { background-color:#889; color:#334 }
 .modal-card-body { background-color:#223 }
 .modal-card-head { background-color:#aab;}
 .hero { background-blend-mode:overlay; background-color:#556 }
}

The snippet above is just for illustration, but you’ll note:

  • Most overrides are background-color and color - simple,
  • Darkening the banner background-image is just overlaying a dark background-color, i.e. background-blend-mode:overlay,
  • Darkening an image (since the page background is dark anyway) is just reducing opacity,
  • In some cases, I had to explicitly use !important.

I didn’t use CSS Variablesvar(--) because Bulma doesn’t either.

Dark Mode with prefers-color-scheme CSS

This media query feature is already supported in the latest versions of Firefox and Safari on macOS 10.14 and Windows 10. The next version of iOS / iPadOS 13 will too. You can check browser support at Can I Use?. Usually, just changing the OS dark mode setting / theme is all that’s needed, unless the change does not get detected by the browser, in which case, just re-load the page.

The downside is that one can’t toggle Dark Mode programmatically with JavaScript. You have to head over to your System Preferences / Control Panel.

Darkmode.js

If programmatic control is your requirement, then it’s just a lot of effort of defining a separate CSS stylesheet and creating a Javascript toggle. But, you could also try to take the easy way out with some Javascript magic...

I stumbled upon darkmode.js which fiddles with CCS mix-blend-mode. I don’t use this, nor endorse it - I just thought it was a cute implementation! The code adds a floating widget, and tries to invert the background color of some elements, including background images. For fun, I’ve added it here for you to play around with. Easy enough to add:

<script src="https://cdn.jsdelivr.net/npm/darkmode-js@1.3.4/lib/darkmode-js.min.js"></script>
<script>
    new Darkmode().showWidget();
</script>

Alas, it does not play nice with Bulma - it fails to invert content within the .box style, and renders the floating widget behind it (as it does not set the z-index).