How to emulate Emulate CSS media feature prefers-color-scheme using JavaScript or CSS?

516 Views Asked by At

How to emulate Emulate CSS media feature prefers-color-scheme using JavaScript or CSS, not in Chrome Developer Tools?

I tried color-scheme: light and color-scheme: dark but doesn't work as expected.

const changeColorSchemeButton = document.querySelector('.change-color-scheme');
const box = document.querySelector('.box');

changeColorSchemeButton.addEventListener('click', function() {
  if (box.classList.contains('color-scheme-dark')) {
    box.classList.remove('color-scheme-dark');
    box.classList.add('color-scheme-light');
  } else {
    box.classList.add('color-scheme-dark');
    box.classList.remove('color-scheme-light');
  }
})
.box {
  width: 200px;
  height: 200px;
  background: red;
  color: blue;
}

.color-scheme-light {
  color-scheme: light;
}

.color-scheme-dark {
  color-scheme: dark;
}

@media (prefers-color-scheme: dark) {
  .box {
    background: grey;
    color: white;
  }
}
<div class="box">
  test
</div>
<button class="change-color-scheme">Change Color Scheme</button>

As you can see, clicking the button will toggle color-scheme-dark and color-scheme-light classes, but the result is the same.

enter image description here

enter image description here

But it's working with Chrome Developers Tool Emulate CSS media feature prefers-color-scheme feature to simulate dark and light modes truly.

enter image description here

How do I truly simulate dark and light modes using JavaScript and CSS?

1

There are 1 best solutions below

1
On

As far as I can read, the color-scheme property only tells the browser which modes your element can be rendered in a comfortable way. And depending on that, you allow the browser to override your colors. But it's not guaranteed that this is happening. You can read more about color-scheme here

But what you can do to automatically set the scheme based on the browser setting and allow the user to switch the mode:

  1. detect the current mode with Javascript
  2. depending on that set a class for your element (or body)
  3. only style your own classes and don't rely on @media (prefers-color-scheme: ...)

Not sure if this is the best way to be honest, but that's how I do it.


In order to detect the users mode you can use window.matchMedia(), if the media query matches, it's dark mode, otherwise it's light mode. So one matchMedia is enough.

const useDark = window.matchMedia("(prefers-color-scheme: dark)");

Then you just set classes for the initial state on your desired element

<br>


if (useDark.matches) {
  box.classList.add('color-scheme-dark');
}
else {
  box.classList.add('color-scheme-light');
}

And in order to manually switch between light and dark mode, toggle those classes in your click event
changeColorSchemeButton.addEventListener('click', function() {
  box.classList.toggle('color-scheme-dark');
  box.classList.toggle('color-scheme-light');
});

Full example below

// detect dark mode
const useDark = window.matchMedia("(prefers-color-scheme: dark)");

// the element you want to apply the color scheme, in your case the .box
const box = document.querySelector('.box');

// if it matches, then it's dark mode, if it doesn't match, it's light mode
// here we set the initial scheme, based on the user setting
if (useDark.matches) {
  box.classList.add('color-scheme-dark');
}
else {
  box.classList.add('color-scheme-light');
}


const changeColorSchemeButton = document.querySelector('.change-color-scheme');

// in your click event, you only have to toggle both classes in order to switch between dark and light mode
changeColorSchemeButton.addEventListener('click', function() {
  box.classList.toggle('color-scheme-dark');
  box.classList.toggle('color-scheme-light');
});
.box {
  width: 200px;
  height: 200px;
  background: red;
  color: blue;
}

.color-scheme-light {
  background: black;
  color: white;
}

.color-scheme-dark {
  background: gray;
  color: white;
}
<div class="box">
  test
</div>
<button class="change-color-scheme">Change Color Scheme</button>