skip to Main Content

I want to provide a "dark mode" switch on a website. That would be easy by using some CSS.

But then: Modern browsers can already tell the website that they want to use a dark mode (prefers-color-scheme). And I can also react to that via CSS.

@media (prefers-color-scheme: dark) {
    html {
        filter: grayscale(0.75) invert(1) contrast(1);
    }
}

My problem is: I do not want these mechanisms (button on the website and browser preference) to collide. And I need the button on the website, because many users don’t know that their browser can change the preference.

Is there any mechanism that would allow a website to provide a button that would change the browser preference?

I fully understand that you would usually not want to allow websites to do something like "change my preferences", however, it seems like a good idea regarding the prefers-color-scheme.

2

Answers


  1. This is a great reference on implementing a dark mode switch.

    The concept is that you:

    1. provide a mode switch which operates within the website, and persist the value of the switch in session storage or local storage so that the mode stays the same as the user browses from page to page;

    2. listen for any changes to the OS dark mode setting and adjust the local setting to match;

    3. if there is no mode in session storage or local storage, such as would happen when a user visits the site for the first time, then read the OS dark mode setting and use that as the initial setting.

    Login or Signup to reply.
  2. I prefer a three-way choice for the user:

    • Use light mode for this page
    • Use dark mode for this page
    • Follow the browser/OS setting.

    Changes to the browser/OS setting are then ignored if the user has explicitly chosen light or dark mode.

    /* This code block simulates localStorage in the sandbox in which the snippet runs. */
    let _darkmode;
    const localStorage = {
      getItem(prop) {
        return _darkmode;
      },
      setItem(prop, value) {
        _darkmode = value;
      }
    };
    /* Omit everything above this line in production. */
    
    function auto() {
      if (localStorage.getItem("darkmode") === "auto" && darkmode.matches)
        document.body.classList.add("darkmode");
      else document.body.classList.remove("darkmode");
    }
    
    function explicit() {
      const value = document.querySelector("select").value;
      localStorage.setItem("darkmode", value);
      switch (value) {
        case "auto":
          auto();
          break;
        case "on":
          document.body.classList.add("darkmode");
          break;
        default:
          document.body.classList.remove("darkmode");
      }
    }
    document.querySelector("select").value =
      localStorage.getItem("darkmode") || "off";
    const darkmode = matchMedia("(prefers-color-scheme: dark)");
    darkmode.addEventListener("change", auto);
    explicit();
    body.darkmode div {
      background: black;
      color: white;
    }
    <div>Text</div>
    <select onchange="explicit()">
      <option value="off">Light</option>
      <option value="on">Dark</option>
      <option value="auto">Auto</option>
    </select>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search