Closed Bug 1547818 Opened 5 years ago Closed 3 years ago

Let add-ons control website's CSS media queries or prefers-color-scheme.

Categories

(WebExtensions :: General, enhancement, P3)

enhancement

Tracking

(Not tracked)

RESOLVED DUPLICATE of bug 1733461

People

(Reporter: 5i13ghzt462u, Unassigned)

References

Details

(Whiteboard: [design-decision-needed])

Background

Firefox 67 introduced the new great prefers-color-scheme for websites. (see Bug 1494034)

Use case

As an add-on, I want to manipulate the light/dark state of web pages independently of the system state and per website, because:

  • users may want a dark system style, but light websites
  • users may want a light system style, but dark websites
  • users generally want more flexibility here
  • users use a system that actually does not support system styles (prefers-color-scheme), e.g. Windows 7, some (non-GNOME?) Linux distros, etc.

If you look on AMO, there are many "dark-style/theme" add-ons, currently applying their own custom CSS. If they, could, however detect that a website offers a "native dark" mode, they could choose that instead of their own custom overwrite.

Problem

After asking on Discourse on how to do that, I got a pretty hard workaround working (thx also to the tips from Stackexchange).

I've later answered my own question on Stackexchange and described the workaround there. Basically I extract the CSS manually and manually apply it. (JS needed, too, BTW…)

You can find it on AMO, if you want to try it out: https://addons.mozilla.org/de/firefox/addon/dark-mode-website-switcher/?src=external-bugzilla (or on GitHub)

Obviously, there are several problems with that approach:

  • As websites likely do not implement separate "prefers-color-scheme: light" it is nearly impossible to force a website to be light, when your system style is dark. Because you would need to have a generic way to "invert" a whole list of CSS or disable existing CSS somehow…
  • As already mentioned, this is a hard and cumbersome workaround to implement.
  • Overwriting the JS alone is very hard because for faking the return value of matchMedia you cannot create a new MediaQueryList. (new MediaQueryList() is not specified/possible.)
  • Even if you all overwrite the JS, you also need to care about the listeners that websites could actually attach to that… yet again, it get's complicated.
  • Also as for CSS media queries, if you only have (prefers-color-scheme: dark) this may be possible, but when websites concatenate multiple factors with and or so, we'll have another level of complexity.
  • After all, as this takes random CSS from websites and re-applies it, this may also easily break websites.

Solution

  • Way 1: Introduce some general way to manipulate media queries/CSS.
  • Way 2: Introduce some way to overwrite "prefers-color-scheme" globally and(/or better) per tab/website.
  • Also, some way to detect whether a website even offers such a mode would be nice. (Okay, you can look through the CSS again, but this is not-so-nice, as I've explained already.)

…for add-ons.

Another advantage this would have:

  • Maybe, we could thus also control all pages, i.e. internal Firefox pages like about:newtab or about:addons (see Bug 1519547), without "serious" (special/many) permissions, as we do not need access to the data directly.

That said, things like Bug 1529323 could eliminate most use cases, but I still think there are many flexible combinations or so that would make sense. (see my listed use cases above.)

Arrgh, now I still forgot the Stackoverflow link, so here it is: https://stackoverflow.com/a/55910185/5008962

Whiteboard: [design-decision-needed]
Component: Untriaged → CSS Parsing and Computation
Product: WebExtensions → Core
Component: CSS Parsing and Computation → Untriaged
Product: Core → WebExtensions

Setting this up as an enhancement for WebExtensions.

Status: UNCONFIRMED → NEW
Type: defect → enhancement
Component: Untriaged → General
Ever confirmed: true

In case I have not shared it already. Here is a direct link to my complicated workaround:

So IMHO that's way to complicated. Remember: all I do there is changing the result of one CSS media feature. And it's not perfect, it still misses a lot of features (I cannot really force a white page when system design is set to dark, actually, because websites likely default to their white design.) And it has a lot of bugs/edge cases of websites that may use arcane combinations of media queries (e.g. display and (prefers-color-scheme: dark) and (min-width: 240px) or so) I can hardly support in any way – without implementing a huge logic for evaluating media queries by myself.

Just my two cents:
Probably the most straight-forward way to expose this would be to add a new browserSetting for this. Maybe something like browserSettings.preferredDocumentColorScheme with possible values "light" and "dark". The default value, if not set by any other extension, being the OS's color setting.

I totally agree BTW. A quick API just to toggle this would be great.

So the Firefox 67 release is soon. So has a decision been done already?
It would be good to know if there is a plan to add such a feature or not.

This is not terribly hard to implement btw, we already have a browser preference for this (ui.systemUsesDarkTheme). It should be straight-forward to make it per-document too, if you stash a bit on the document:

https://searchfox.org/mozilla-central/rev/80a3d06820b31e1d95beb582f15e789cda9f6e03/layout/style/nsMediaFeatures.cpp#245

I think a decision needs to be made as to whether this bug is about controlling arbitrary media queries, or just prefers-color-scheme. The latter would be much easier to implement, but I don't really want to implement it as a separate feature if we're eventually going to wind up implementing the former anyway.

Yeah, thanks FYI. That said, it seems not to be visible/predefined in Firefox Nightly, as far as I see.

But yeah, I can set ui.systemUsesDarkTheme to 1 and hmm, it seems to work. (But it needs some doc.)


Generally, BTW, if you implement such a setting for switching ui.systemUsesDarkTheme also remember I, as an add-on maker, may also want to know whether the current page uses prefers-color-scheme, because if not, I may want to inject custom CSS for making it look dark.

I think a decision needs to be made as to whether this bug is about controlling arbitrary media queries, or just prefers-color-scheme.

So… when will a decision being made?

Should I possibly create a new issue for toggling ui.systemUsesDarkTheme via an add-on? IMHO, this seems like the easier way and if I would have to choose, I would choose this. (as said, easy and I don't know what use cases there are for modifying other media queries. Maybe only the other new ones for prefers-reduced-motion, i.e. these for accessibility. However, then there is the question why would you want to disable/toggle that?)

Another use case to consider:

  • As an add-on I may want to provide the ability to switch only the current tab/website to a dark or light theme.

(With media queries this would likely be possible.)

(In reply to rugk from comment #9)

I think a decision needs to be made as to whether this bug is about controlling arbitrary media queries, or just prefers-color-scheme.

So… when will a decision being made?

Should I possibly create a new issue for toggling ui.systemUsesDarkTheme via an add-on? IMHO, this seems like the easier way and if I would have to choose, I would choose this. (as said, easy and I don't know what use cases there are for modifying other media queries. Maybe only the other new ones for prefers-reduced-motion, i.e. these for accessibility. However, then there is the question why would you want to disable/toggle that?)

It's not that simple, as ui.systemUsesDarkTheme should change automatically to the correct option when the system Dark Mode setting is changed. What would happen if Dark Mode was toggled in the OS, should the Firefox option then be set to the real value or should it be locked completely from change by the OS? If so, how would that be communicated clearly to the user?

It seems wrong to me that ui.systemUsesDarkTheme should be able to lie about whether the systemUsesDarkTheme. IMO that value should always reflect the reality of the system settings. Adding another option, like Alexander Schlarb suggested, seems more proper.

Priority: -- → P3

Another use-case for you: As a developer, I want to be able to manipulate media queries (especially prefers-color-scheme) to test my website in different modes.

Currently I use prefers-color-scheme: dark by default, but to test the non-dark theme of my website I've got to dive into about:config and fiddle around. I'd really like to just be able to be able to click a button (e.g. through an extension) to test it in different prefers-color-scheme modules.

(also, I did try the extension linked to above, but it didn't work for me)

(also, I did try the extension linked to above, but it didn't work for me)

I am the author of that extension. So if you find a bug/non-working site, it would be kind of you to report it on GitHub: https://github.com/rugk/website-dark-mode-switcher
Thanks.

@rugk: Ah, I sure! I didn't realise it was open-source on GH. I'll open an issue then :-)

For me, ui.systemUsesDarkTheme does not work because privacy.resistFingerprinting overrides it. I know why/the implications, but I would still want to use dark theme and keep the remaining of privacy.resistFingerprinting (same goes for HiDPI, for which I have another ticket).

Thus, for now @rugk extension is the only way I can have the dark theme here on Bugzilla for instance. And then a good API for the extension to manipulate this more easily would be welcome.

After looking a bit around, the best entry point would be the Document::PrefersColorScheme in dom/base/Document.cpp.

StylePrefersColorScheme Document::PrefersColorScheme(
    IgnoreRFP aIgnoreRFP) const {
  if (aIgnoreRFP == IgnoreRFP::No &&
      nsContentUtils::ShouldResistFingerprinting(this)) {
    return StylePrefersColorScheme::Light;
  }

  if (auto* bc = GetBrowsingContext()) {
    switch (bc->Top()->PrefersColorSchemeOverride()) {
      case dom::PrefersColorSchemeOverride::Dark:
        return StylePrefersColorScheme::Dark;
      case dom::PrefersColorSchemeOverride::Light:
        return StylePrefersColorScheme::Light;
      case dom::PrefersColorSchemeOverride::None:
      case dom::PrefersColorSchemeOverride::EndGuard_:
        break;
    }
  }

  if (nsPresContext* pc = GetPresContext()) {
    if (pc->IsPrintingOrPrintPreview()) {
      return StylePrefersColorScheme::Light;
    }
  }

  const bool dark =
      !!LookAndFeel::GetInt(LookAndFeel::IntID::SystemUsesDarkTheme, 0);
  return dark ? StylePrefersColorScheme::Dark : StylePrefersColorScheme::Light;
}

So, allowing extensions to alter the browsingContext.prefersColorSchemeOverride would match.

Yeah, though that is used by the devtools color scheme emulation so probably you need at least one more bit to distinguish those.

It’s my bad I missed this bug when posting bug 1733461, but there is a now is a webextension preference interface for this. It allows to get, set, and watch the layout.css.prefers-color-scheme.content-override preference introduced in bug 1722886. Allowed values are currently "dark", "light", "system", or "browser", see bug 1529323.

Currently that preference change is not propagated to pages however, a refresh is needed.

(In reply to Cimbali from comment #18)

It’s my bad I missed this bug when posting bug 1733461, but there is a now is a webextension preference interface for this. It allows to get, set, and watch the layout.css.prefers-color-scheme.content-override preference introduced in bug 1722886. Allowed values are currently "dark", "light", "system", or "browser", see bug 1529323.

Duping

Currently that preference change is not propagated to pages however, a refresh is needed.

I think bug 1736163 might fix this? emilio would know.

Status: NEW → RESOLVED
Closed: 3 years ago
Resolution: --- → DUPLICATE

Yep, it should.

Does bug 1733461 allow overriding this on a per tab / per site basis? I don't see how it addresses (most of) the use cases in this bug...

@Tech Han Hui opened Bug 1849786 specifically about that now.

You need to log in before you can comment on or make changes to this bug.