How to change media-query using JS?

Asked

Viewed 188 times

1

I’m using CSS with media queries, for example:

html {
  --color: #OOOOOO;
}


@media (prefers-color-scheme: dark) {
 html {
   --color: #FFFFFF;
 }
}

Considering the code above, who has the prefers-color-scheme of dark will have #FFFFFF and those who don’t will see #000000. No problem so far.

However, someone may prefer to view content other than the current one. For example, considering that your prefers-color-scheme is of light. If you want to view the content as if it were dark you have to go to your browser settings and change.

Is there any way in JS to override the browser setting? Force you to become one prefers-color-scheme: dark?!


Is there any way to overwrite these parameters using Javascript? Something like:

window.document .MediaQueries .Set("prefers-color-scheme", "dark");

Thus, regardless of the current "prefers-color-Scheme" of the browser, it would become "dark" and nothing in CSS would have to be changed.


This is possible somehow?


I used the prefers-color-scheme to better illustrate the problem, but consider seeing the previous post.

  • 1

    You could do it using @custom-media(Chapter 4 and 4.1) but the recommendation so far has not been implemented in any browser.

1 answer

0

I found a solution, that would be using cssRules, that the @Augusto Vasques mentioned in a comment.


This isn’t exactly how I wanted it, it won’t work with more complex media queries (example: min-width). For it to work it would require you to create some dictionary to then retrieve the old values.

Considering, exactly:

html {
  --color: #OOOOOO;
}


@media (prefers-color-scheme: dark) {
 html {
   --color: #FFFFFF;
 }
}

If we were running the browser with light, the color will be #OOOOOO. My question would be how to change the browser to dark, unfortunately this has no way and I will mark any other reply as valid that does just that.

What we have to do is change the @media (prefers-color-scheme: dark) for @media (prefers-color-scheme: light), this way the second variable will override the previous one. So how are you like light will now use #FFFFFF, because the dark of CSS turned light.


To do this magic there is the cssRules, as I mentioned before. In total, my code was something like:

JS:

// Quando tiver mais tempo dou uma organizada no código, porque nem eu estou entendendo, simplesmente copiei o que fiz em Golang. Deve ter como fazer melhor em JS.


window.document.querySelector("fullscreen").addEventListener("click", function(e) {
  if (!(e.target instanceof HTMLButtonElement)) {
    return;
  }

  if (IsBrowser(e.target.dataset.mode)) {
    SetTheme("light", "dark"); // Mudamos para o padrão, já que quer usar aquilo que o seu navegador já é.
  } else {
    SetTheme("dark", "light"); // Mudamos para o oposto ao seu navegador (porque se estiver como "dark" o CSS virá "light"; se estiver usando como "light" passará a ser "light" e então o modo noturno será ativado).
  }
});

window.matchMedia("(prefers-color-scheme: light)").addEventListener("change", function (_) {
  SetTheme("light", "dark"); // Se você mudar no browser voltamos ao modo normal do CSS.
})


function IsBrowser(t) {
  return window.matchMedia("(prefers-color-scheme: " + t + ")").matches;
}

function SetTheme(o, n) {
  let rules = window.document.styleSheets[0].cssRules;
  for (i = 0; i < rules.length; i++) {
    media = rules[i].media
    if (media == undefined) {
      continue
    }

    current = media.mediaText
    current = current.replace("(prefers-color-scheme: " + o + ")", "(prefers-color-scheme: " + n + ")");

    rules[i].media.mediaText = current
  }
}
html {
  --background: aqua;
}

@media (prefers-color-scheme: dark) {
  html {
    --background: brown;
  }
}

fullscreen {
  display: block;
  height: 100vh;
  width: 100vw;
  background-color: var(--background);
}
<fullscreen>
  <button data-mode=dark>Escuro</button>
  <button data-mode=light>Claro</button>
</fullscreen>

Golang:

func SetTheme(old, new string) {
    rules := js.Global.Get("document").Get("styleSheets").Index(0).Get("cssRules")
    for i := 0; i < rules.Length(); i++ {
        media := rules.Index(i).Get("media")
        if media == js.Undefined {
            continue
        }

        current := media.Get("mediaText").String()
        current = strings.Replace(current, `(prefers-color-scheme: `+old+`)`, `(prefers-color-scheme: `+new+`)`, -1)
        media.Set("mediaText", current)
    }
}
  • 1

    Why was the answer negative? Could explain the flaw in the HR reasoning or what part of the answer does not work?

Browser other questions tagged

You are not signed in. Login or sign up in order to post.