6

We can use prefers-color-scheme: dark to detect if dark mode is activated or not:

const isDarkMode = window.matchMedia('(prefers-color-scheme: dark)').matches;

Is there a way detect if a browser supports dark mode at all? (By "supports dark mode" I mean the browser automatically changes the default background/text colors of web pages).

In CSS, we can force dark mode with

color-scheme: dark;

however, some browsers (Firefox for Android) will ignore it. So I'd like to hide theme selection if dark mode is not available.

TylerH
  • 20,799
  • 66
  • 75
  • 101
vanowm
  • 9,466
  • 2
  • 21
  • 37
  • not sure on detecting but you can easily look quickly here https://caniuse.com/?search=color%20scheme – Brent Nov 13 '21 at 17:24
  • What do mean by when it's available?, Dark mode is something that you add to the website. If you want to detect whether the browser can detect the OS mode do as you mentioned on the question. is there something that I'm missing? – Mohamed Abdallah Nov 13 '21 at 17:35
  • @MohamedAbdallah We can force dark mode in CSS with `color-scheme: dark;` but not all browsers will switch to dark mode (i.e. Android Firefox). – vanowm Nov 13 '21 at 17:37
  • 2
    You could try to base your detection on CSS's `@supports (color-scheme: dark) { ... }`. – connexo Nov 13 '21 at 20:56
  • @connexo interesting. Any ideas why its "true" when used any string instead of `dark` ? For example `@supports (color-scheme: blahblahblah) { background-color: red; }` – vanowm Nov 13 '21 at 21:31

1 Answers1

0

My current solution is to switch between dark and light mode and check if default color has changed between the modes:

const hasDarkMode = function()
{
  const el = document.createElement("div");
  el.style.display = "none";
  document.body.appendChild(el);
  let color;
  /*canvastext - doesn't work in Samsung Internet, initial/unset - doesn't work in Firefox*/
  for(let i = 0, c = ["canvastext", "initial", "unset"]; i < c.length; i++ )
  {
    el.style.color = c[i];
    el.style.colorScheme = "dark";
    color = getComputedStyle(el).color;
    el.style.colorScheme = "light";
    color = color != getComputedStyle(el).color;
    if (color)
      break;
  }
  document.body.removeChild(el);
  return color;
}();

console.log("Dark mode supported:", hasDarkMode);

This might not be the most elegant solution, but it seems to be working.

With comment from @connexo we can also test with:

const hasDarkMode = CSS.supports("color-scheme", "dark");

console.log("Dark mode supported:", hasDarkMode);
@supports (color-scheme: dark)
{
  .no-dark-mode
  {
    display: none;
  }
}
<div>Dark mode is <span class="no-dark-mode">not </span>available</div>
vanowm
  • 9,466
  • 2
  • 21
  • 37