Add support for CSS prefers-color-scheme media feature

RESOLVED FIXED in Firefox 67

Status

()

enhancement
P3
normal
RESOLVED FIXED
8 months ago
a day ago

People

(Reporter: merihakar, Assigned: mats, Mentored)

Tracking

(Depends on 1 bug, Blocks 3 bugs, {dev-doc-complete})

Trunk
mozilla67
Points:
---
Dependency tree / graph

Firefox Tracking Flags

(firefox64 wontfix, firefox65 wontfix, firefox66 wontfix, firefox67 fixed)

Details

Attachments

(1 attachment, 3 obsolete attachments)

Reporter

Description

8 months ago
A new media query is added to CSS Media Queries Level 5 to utilize the dark mode preference operating systems provide.

https://drafts.csswg.org/mediaqueries-5/#prefers-color-scheme
Priority: -- → P3
Status: UNCONFIRMED → NEW
Ever confirmed: true
https://paulmillr.com/posts/using-dark-mode-in-css/ is a post about implementation of this feature in Safari; https://webkit.org/blog/8475/release-notes-for-safari-technology-preview-68/ documents its addition.

I think if we implement this we may want to provide an hidden (about:config) preference to express a preference on platforms where the OS doesn't have one.
Bug 1466335 implemented a similar proprietary media query for Mac, bug 1368808 for Windows.

(In reply to David Baron :dbaron: 🇫🇷 ⌚UTC+2 from comment #1)
> https://paulmillr.com/posts/using-dark-mode-in-css/ is a post about
> implementation of this feature in Safari;
> https://webkit.org/blog/8475/release-notes-for-safari-technology-preview-68/
> documents its addition.
> 
> I think if we implement this we may want to provide an hidden (about:config)
> preference to express a preference on platforms where the OS doesn't have
> one.

I believe this also already works via ui.systemUsesDarkTheme.
Depends on: 1466335, 1368808
OS: Mac OS X → All
Summary: Add support for CSS prefers-color-scheme media feature for macOS → Add support for CSS prefers-color-scheme media feature
I was hacking this over my lunch and managed to get the following working:

* { background: yellow; } // Applies to anyone without the pref override

@media (prefers-color-scheme) {  // Applies to anyone with the pref override
  * { background: red; }
}

@media (prefers-color-scheme: dark) {  // Applies to anyone with the pref set to 1
  * { background: blue; }
}

@media (prefers-color-scheme: light) { // Applies to anyone with the pref set to 0
  * { background: pink; }
}

Is this the expected behavior?
Comment on attachment 9021821 [details]
Bug 1494034 - Intial work for adding prefer-dark-theme media query.

With the right tests is this enough to get this supported? Should we not send the light mode ever?
Attachment #9021821 - Flags: feedback?(emilio)
Taking for now, I'm just working on this in my own time though.
Assignee: nobody → jkt
Comment on attachment 9021821 [details]
Bug 1494034 - Intial work for adding prefer-dark-theme media query.

It does look reasonable to me.

We don't have a `prefers-light-theme` thing, maybe `(prefers-color-scheme: light)` should always evaluate to false? Worth checking what other browsers do.

Similarly for what `(prefers-color-scheme)` evaluates to. The spec doesn't seem to mention anything. We should file a spec issue.

----

I just took a look at WebKit's source, and it doesn't make sense to me:

  http://webkit.crisal.io/webkit/rev/6e4aafe0e39c8d49ad33a31b9b22a2dd65192c25/Source/WebCore/css/MediaQueryEvaluator.cpp#731

The semantics WebKit implements looks wrong. Safari seems to evaluate '(prefers-color-scheme: no-preference)' to true all the time, regardless of the actual user preference.

Similarly it seems to implement light: !dark, which also seems slightly wrong.

Finally, Safari seems to flat out reject `(prefers-color-scheme)` at parse time. That is:

  matchMedia("(prefers-color-scheme)").media == "not all"

That seems unfortunate. We could implement such a thing adding another ParsingRequirements thing, but I think that always evaluating to false instead but parsing is better, since we need to eventually implement bug 1469173 which would end up with such behavior anyway.

In any case, we should:

 * Implement what WebKit implements and file spec issues, or:
 * Implement saner things and file spec issues and potentially file WebKit bugs, or:
 * Only file spec issues and hold off on the implementation.

I'd be ok with any of these, though I'd prefer (2) or (3), provided we send a PSA to dev-platform@ and people agree.
Attachment #9021821 - Flags: feedback?(emilio) → feedback+
I raised a spec issue for some clarification: https://github.com/w3c/csswg-drafts/issues/3278

I would like to see this tied to the dark/light theme if it makes sense to do so for non supporting systems.
Blocks: 1459504
Blocks: 1488384

Comment 9

4 months ago

Thinking aloud slightly, what should the media query match while printing? Light, because paper? Always false, because it's only meaningful on screens?

That's a good question. I think we shouldn't intermix the concept of printing and the user theme preference, but I could see the argument for the opposite.

Maybe worth filing an issue in https://github.com/w3c/csswg-drafts?

Also, Jonathan, are you actively working on this? Chromium is implemented, so it'd be great not to lag behind much given our spec questions were answered. Let me know if you want me (or someone else, quasicomputational? :)) to take over or what not (I'll make sure that the patch appears as co-authored by you of course).

Flags: needinfo?(jkt)

Went ahead and filed https://github.com/w3c/csswg-drafts/issues/3522.

I don't mind taking this on, but I do think there's still some spec work to be done. On the other hand, both Chromium and Safari are gearing up to ship, so who knows if that'll get done before the current version's ossified...

I don't have cycles to complete this right at the moment, so if people want to take it on that is fine with me :).

but I do think there's still some spec work to be done.

Yeah I was kinda waiting for this to resolve before working on this further.

Thanks!

Flags: needinfo?(jkt)

Ok, I'll clear the assignee for now :)

Assignee: jkt → nobody
Mentor: emilio
Assignee

Comment 14

4 months ago

I agree with this comment:
https://github.com/w3c/csswg-drafts/issues/3278#issuecomment-452834498
In particular:

@media (prefers-color-scheme)
Simply means that the webbrowser at hand supports communicating it's users color-scheme preference.

so, I guess that means:

None => return prefers_dark_theme

should be:

None => return true

Other than that, is there anything else that needs fixing here?

Flags: needinfo?(emilio)

Well, adding tests, but yeah.

Flags: needinfo?(emilio)
Assignee

Comment 16

4 months ago

OK, I made a few updates to reflect the latest spec issues, and I'll add some tests too...

Assignee: nobody → mats
Assignee

Comment 17

4 months ago
Posted patch fix+tests (obsolete) — Splinter Review

A few substantial changes based on feedback in the github issues:

  • if presContext->IsPrintingOrPrintPreview() is true, then return "light"
  • if we fail to retrieve the LookAndFeel::eIntID_SystemUsesDarkTheme value, then return "no-preference" (this is currently the case for GTK: bug 1525775)
  • we already have an integer pref, ui.systemUsesDarkTheme, where 0 means "light" and 1 means "dark"; I'm extending that so that 2 means "no-preference". This makes the name a slight misnomer, but I think it's more user friendly to continue to use the same name so that existing usage of this pref works as before rather than introducing a new (non-binary) name. It's a hidden pref anyway, so naming isn't that important.
  • made "@media (prefers-color-scheme)" return true, since we now support this feature
  • added reftests

Probably worth waiting a few more days until we have CSSWG resolutions on the github issues before we finalize this. I've added Agenda+ on both issues so hopefully we'll have answers soon. (Feel free to punt on the review until then if you wish.)

https://treeherder.mozilla.org/#/jobs?repo=try&revision=1841c5b4d825e8f5f16c8ac74795f1c35f6654c4

Attachment #9021821 - Attachment is obsolete: true
Attachment #9042706 - Flags: review?(emilio)
Comment on attachment 9042706 [details] [diff] [review]
fix+tests

Review of attachment 9042706 [details] [diff] [review]:
-----------------------------------------------------------------

Looks good with those addressed, assuming the CSSWG resolves as you expect, thanks!

Let me know if you want me to do another once-over after addressing the comments or what not.

Feel free to either wait for a CSSWG resolution or not, as long as we address any possible changes ASAP.

::: layout/style/GeckoBindings.h
@@ +802,5 @@
> +// Return values have the following meaning:
> +// 0: light
> +// 1: dark
> +// 2: no-preference
> +// anything else: the user has set the ui.systemUsesDarkTheme pref to an invalid value.

Can we instead return a StylePrefersColorScheme directly? You'd need to make the enum `pub` in rust for that to work. You can follow the pattern DisplayMode / StyleDisplayMode uses.

::: layout/style/nsMediaFeatures.cpp
@@ +243,5 @@
> +{
> +  if (nsContentUtils::ShouldResistFingerprinting(aDocument)) {
> +    return 0; // "light"
> +  }
> +  if (nsIDocShell* docShell = aDocument->GetDocShell()) {

Why doesn't just aDocument->GetPresContext() work?

::: servo/components/style/gecko/media_features.rs
@@ +364,5 @@
> +    };
> +
> +    let prefers_color_scheme =
> +        unsafe { bindings::Gecko_MediaFeatures_PrefersColorScheme(device.document()) };
> +    match query_value {

Then this will just become `query_value == prefers_color_scheme`.
Attachment #9042706 - Flags: review?(emilio) → review+
Assignee

Comment 19

3 months ago
Posted patch fix+tests (obsolete) — Splinter Review
Attachment #9042706 - Attachment is obsolete: true
Attachment #9042753 - Flags: review?(emilio)
Assignee

Comment 20

3 months ago

So it appears we now pass all the tests in
https://searchfox.org/mozilla-central/source/testing/web-platform/tests/css/mediaqueries/prefers-color-scheme.html
except the last one:
https://treeherder.mozilla.org/#/jobs?repo=try&revision=3247feecfcb9c376928afa0e9ec66a5235552d6d&selectedJob=227451411
which appears to test that "(prefers-color-scheme)" is always
the exact opposite of "(prefers-color-scheme: no-preference)".

This looks like a bogus test to me, at least with the assumption
that "(prefers-color-scheme)" is always true in an UA that
supports this feature (like we do with this patch).

Comment on attachment 9042753 [details] [diff] [review]
fix+tests

Review of attachment 9042753 [details] [diff] [review]:
-----------------------------------------------------------------

Yeah, I'll make sure we address whatever changes as a result of https://github.com/w3c/csswg-drafts/issues/3278, or update the WPT test / file a chromium bug.
Attachment #9042753 - Flags: review?(emilio) → review+
Assignee

Comment 22

3 months ago
Posted patch fix+testsSplinter Review

Updated per clarifications from CSSWG. Intradiff:

 fn eval_prefers_color_scheme(device: &Device, query_value: Option<PrefersColorScheme>) -> bool {
-    let query_value = match query_value {
-        Some(v) => v,
-        None => return true,
-    };
-
     let prefers_color_scheme =
         unsafe { bindings::Gecko_MediaFeatures_PrefersColorScheme(device.document()) };
-    query_value == prefers_color_scheme
+    match query_value {
+        Some(v) => prefers_color_scheme == v,
+        None => prefers_color_scheme != PrefersColorScheme::NoPreference,
+    }
 }

Attachment #9042753 - Attachment is obsolete: true
Attachment #9044088 - Flags: review?(emilio)
Comment on attachment 9044088 [details] [diff] [review]
fix+tests

I've only looked at the intradiff, but looks good, thanks!

Please send an intent email when landing :)
Attachment #9044088 - Flags: review?(emilio) → review+

Well I guess you also need to remove the test expectations for the test mentioned in comment 20.

Oh, it's already in the patch, nvm :)

Comment 27

3 months ago
Pushed by mpalmgren@mozilla.com:
https://hg.mozilla.org/integration/mozilla-inbound/rev/4739353088fc
Add support for CSS prefers-color-scheme media feature.  r=emilio

Comment 28

3 months ago
bugherder
Status: NEW → RESOLVED
Last Resolved: 3 months ago
Resolution: --- → FIXED
Target Milestone: --- → mozilla67

Updated

3 months ago
Depends on: 1529323

Comment 29

3 months ago

Just tested this on Nightly 67.0a1 (2019-02-22) on macOS. It detects the OS theme correctly, but it doesn't adapt to theme changes like Safari does, not even after reloading the page. You need to completely quit the browser and restart it for a new theme to be considered. window.matchMedia('(prefers-color-scheme: dark)').addListener() handlers are also not fired (they are in Safari).

(In reply to felix.b from comment #29)

Just tested this on Nightly 67.0a1 (2019-02-22) on macOS. It detects the OS theme correctly, but it doesn't adapt to theme changes like Safari does, not even after reloading the page. You need to completely quit the browser and restart it for a new theme to be considered. window.matchMedia('(prefers-color-scheme: dark)').addListener() handlers are also not fired (they are in Safari).

That's bug 1528960.

Depends on: 1525775
See Also: → 1523990
Depends on: 1532850

Updated

2 months ago
Depends on: 1540726

Hey! This bug has been marked as fixed in v67. I'm using 67.0b8 (64-bit) on Ubuntu 18.10 (with the Unity desktop) - how do I use this & setup my preference to dark?

(In reply to Starbeamrainbowlabs from comment #31)

Hey! This bug has been marked as fixed in v67. I'm using 67.0b8 (64-bit) on Ubuntu 18.10 (with the Unity desktop) - how do I use this & setup my preference to dark?

Should be auto-detected from your GTK theme, and you can override it setting ui.systemUsesDarkTheme to 1.

(In reply to Emilio Cobos Álvarez (:emilio) from comment #32)

(In reply to Starbeamrainbowlabs from comment #31)

Hey! This bug has been marked as fixed in v67. I'm using 67.0b8 (64-bit) on Ubuntu 18.10 (with the Unity desktop) - how do I use this & setup my preference to dark?

Should be auto-detected from your GTK theme, and you can override it setting ui.systemUsesDarkTheme to 1.

Ah, I see - thanks! I don't know how to alter my GTK theme, so I'll just adjust the conf setting :-)

Update: I've set ui.systemUsesDarkTheme to 1, but the demo on MDN is not functioning for me - it's showing as black text on white, instead of white-on-black. Is it because it's in an iframe or something? Or is the feature in the next beta? I did have to create the about:config setting as it didn't already exist yet.

Hardware: x86_64 → All

I've added a note about this to the Fx 67 rel notes:
https://developer.mozilla.org/en-US/docs/Mozilla/Firefox/Releases/67#CSS

And it looks like some kind soul documented this already!

https://developer.mozilla.org/en-US/docs/Web/CSS/@media
https://developer.mozilla.org/en-US/docs/Web/CSS/@media/prefers-color-scheme

Thanks to whoever that was ;-)

I'd appreciate a tech review of this content.

Fixed it! After carefully re-reading this, you need to create the new about:config directive to be an integer, not a string. If you do accidentally create a string, then you'll need to close Firefox and edit your prefs.js file to correct it, as about:config does not appear to be capable of this at the moment.

Dark Mode is available on this Bugzilla as of yesterday and now featured in the Hacks blog post for Firefox 67. Dark Mode itself has been planned for a while but prefers-color-scheme has become a trigger for us. Thanks everyone for making this happen!

Updated

a day ago
Depends on: 1554047
You need to log in before you can comment on or make changes to this bug.