#696: Dark mode support for web apps

Visit on Github.

Opened Dec 9, 2021

Braw mornin' TAG!

I'm requesting a TAG review of dark mode support for web apps.

This feature adds a user_preferences manifest member which allows apps to specify a different theme color and background color for dark mode and other user preferences in the future.

"user_preferences": {
    "color_scheme_dark": {
        "theme_color": "#000"
        "background_color": "#000"
    }
  }

Further details:

We'd prefer the TAG provide feedback as:

💬 leave review feedback as a comment in this issue and @-notify loubrett

Discussions

Comment by @cynthia Dec 20, 2021 (See Github)

High-level first pass question: While the user needs make a lot of sense, wouldn't putting it into only manifests be problematic for non-installable webapps?

Comment by @loubrett Dec 21, 2021 (See Github)

It is already possible to define this in CSS - adding it to the manifest allows these colors to be used while the app is opening, before the page has loaded.

Discussed Feb 1, 2022 (See Github)

Tess: I was involved ... i think it's fine ... i wish there was more alignment between CSS and web manifest in terms of how things are expressed. But two languages are under diffeent constraints considering processors that handle web manifest files and how much of the web stack is available to that processor... certainly they ended up with a solution that's fairly simple and extensible to other theme color type things... like having colorscheme .. seems sensible to me. These are initial thoughts.

Dan: they punted on s&p review, does it make much of a difference? Information already exposed through CSS. Multistakeholder support? After incubation?

Peter: colour scheme and a set of keys rather than colour scheme _ is more fragile for extensibility. How adding more css colour scheme media features fits in, if they're putting values with the key names

Tess: fair feedback. Doesn't seem that bad now because they only have this once case, but adding more gets ugly

Peter: only dark and light right now, but others might be defined in the future

Dan: punt to next week

Discussed Feb 1, 2022 (See Github)

punted to plenary

Discussed Feb 1, 2022 (See Github)

Tess: Peter raised the point that it's weird they're combining properties and values, media features and values, in the keys. Their response is basically about keeping structure simple, less nesting. I don't think the latter falls from the former. If I'm writing code the difference between Peter's suggestion and what they have is a quesitno of where you end the string and where you put the brackets. From a dev perspective they're equally simple.

Rossen: from an extensibility point of view..

Tess: also broadly equivalent.. Preference for less nesting feels like a personal preference of the feature designers as opposed to something justified on simplicity grounds, because I don't think it's any simpler. It's valid, but doesn't strike me as the strongest argument

Peter: if i want to iterate through all the colours chemes specified I need to start parsing keys

Tess: great followup point, that's why they're not the same

Rossen: my reaction too. Jamming in values along with the attributes of properties in this case syntactically, Tess, I agree with what you said. You could put them in the same line or space them with new lines and braces. But dark and light and everything else that's gonna come up are values of that property we all know so combining them together leads to all kinds of residiual issues like the one Peter pointed out. Stronger arguement to put them on a separate level

Tess: worth replying ot the last comment pointing out that they didn't take your point that iterating over these would require parsing keys and in the other design it wouldn't. That's absent from their reply.

Peter: on the other side, I do reall having this conversation before about something else in th emanifest and they took the same appraoch. So if there's consistentcy..

Tess: cnsistency on the platform is nice when we manage to pull it off. Overall there is lots of inconsistency. All things being equial, consistency is nice, but in this case there's a real downside to this design that you've identified. Might be worth not being consistent with other bad things.

Peter: perpetuating a bad pattern

Tess: I can leave feedback, these aren't interchangeable for that reason

Dan: Lea has left a couple of comments in the meantime. Also while we were speaking my computer has turned to dark mode and github has gone from light to dark.

Lea: comment I left was not immediately related to this discussion. They said it's already definable through CSS - what are they referring to? Custom properties for theme colours? SOmething I don't know about? Assuming it is definable through CSS why would we duplicate it into a different API? What if you could link to a stylesheet that defines these very eseential things that you want a splash screen to have access to before the app loads. Takes an extra request, but so do other things in the manifest like icons.

Tess: linking to a css file from the manifest would mean that the manifest parser would have to have a css parser in it .. big ask

Lea: true. Fair enough. Down the line, what if we need to duplicate more CSS in the manifest?

Tess: oh yeah, your worry is very well-placed

Rossen: yoru point is generally speaking something I agree with. We had this conversation about how much of the platform you expose to the manifest and end up duplicating. But from the app packaging point of view it's been a hard argument to come around on either side. Not the hill we want to die on.

Lea: agreed. I can edit to add the part about the CSS parser.

Tess: need to take some time to write a comment

Comment by @torgo Feb 10, 2022 (See Github)

@loubrett - Hi Just having a look at this on our call today. One question - I'm assuming this would go to webapps wg after incubation?

Comment by @plinss Feb 10, 2022 (See Github)

I'm curious why the choice of:

"user_preferences": {
    "color_scheme_dark": {
        "theme_color": "#000",
        "background_color": "#000"
    },
    "color_scheme_light": {
        "theme_color": "#fff",
        "background_color": "#fff"
    }
 }

vs. something like:

"user_preferences": {
    "color_scheme": {
        "dark": {
            "theme_color": "#000",
            "background_color": "#000"
        },
        "light": {
	        "theme_color": "#fff",
	        "background_color": "#fff"
        }
    }
}

The latter seems more friendly to extensibility (e.g. easier to handle should more color schemes be added, i.e. no need to parse keys). Either way I'd like to see some examples of how other user preference media features would be specified and make sure that a common pattern emerges in the keys.

Comment by @cynthia Feb 12, 2022 (See Github)

That's an interesting point, if we ever need to extend for other user needs (e.g. high contrast comes to mind) the latter pattern feels like it would be nicer.

Comment by @loubrett Feb 14, 2022 (See Github)

The keys are based off css media queries by removing the 'prefers' and adding the value at the end. Some other examples that could be added in the future are contrast_less, contrast_more, forced_colors_active. So if more color schemes are added these will be color_scheme_x.

We also want the structure of this field to match the proposed translations structure .

I think it is good to try and keep the structure as simple as possible while allowing for extensibility, so less nesting is preferable.

I'm assuming this would go to webapps wg after incubation?

Yes that's the plan.

Comment by @LeaVerou Feb 14, 2022 (See Github)

It is already possible to define this in CSS - adding it to the manifest allows these colors to be used while the app is opening, before the page has loaded.

How? Are you referring to accent-color, custom properties, or something else? If this is already definable in CSS (?), should we have two different APIs for it? What if the manifest could just link to a CSS file that specifies certain things that the splash screen can utilize? That requires a separate request, but so do other things in the manifest already. It also introduces a dependency for a CSS parser for manifest parsing which may be a bigger problem, but thought we'd mention it anyway.

Comment by @loubrett Feb 14, 2022 (See Github)

It's possible using CSS media queries (specifically the prefers-color-scheme feature).

This is very similar to the existing theme_color and background_color manifest fields which can also be defined in CSS. The manifest values are used before the stylesheet as loaded.

Depending on the CSS parser was suggested in the original thread for this, however it was decided that should be avoided due to the complexity.

Comment by @hober Feb 14, 2022 (See Github)

@loubrett wrote:

I think it is good to try and keep the structure as simple as possible while allowing for extensibility

All things being equal, simpler is better, yes. But I don't think your proposed structure & @plinss' alternative are equal. Specifically:

The keys are based off css media queries by removing the 'prefers' and adding the value at the end. […I]f more color schemes are added these will be color_scheme_x.

Using key names that mix names and values together like this suffers from the problem @plinss identified, namely, in order to iterate over these things, you have to parse the microsyntax used for the key names. Using a structure that has one more level of nesting, as @plinss suggested, would avoid this problem.

We also want the structure of this field to match the proposed translations structure .

But the translations structure looks like @plinss' suggestion and not what you ended up with! For instance, see this example from the translations explainer:

{
  "name": "Good dog",
  "description": "An app for dogs",
  "icons": [],
  "screenshots": [],
  "lang": "en",
  "translations": {
    "fr": {
      "name": "Bon chien",
      "description": "Une application pour chiens",
      "icons": [],
      "screenshots": []
    }
  },
}

If the translations structure was like yours, we'd see a flatter structure with a "translation_fr" key in it.

Comment by @loubrett Mar 22, 2022 (See Github)

Another reason in favor of less nesting is that we may need to use the order of objects in the future. So if multiple preferences match, we would use the one defined first.

Discussed Apr 1, 2022 (See Github)

Dan: comment responding to Tess's point

Peter: not sure I buy that comment. It's just JSON.. if you have multiple matching key in JSON the last one wins in a JSON parser?

Tess: yes

Peter: so if they say first one wins they write a custom JSON parser? What?

Tess: seems like completely missed the point. They even said they wanted it to be consistent with that other thing, and Peter's proposal is consistent and their proposal isn't... Someone should point out that's not how JSON works.

Discussed Apr 1, 2022 (See Github)

Dan: Pending feedback, Peter left a comment..

Sangwhan: can nudge

Comment by @torgo Apr 4, 2022 (See Github)

Hi Louise - we just discussed this in today's TAG call and we really think you should take another look at Peter's suggestion from the 10th of Feb.

Comment by @plinss Apr 4, 2022 (See Github)

So if multiple preferences match, we would use the one defined first.

I don't believe that's how JSON works, are you proposing requiring a custom parser for the manifest file?

Discussed May 1, 2022 (See Github)

Peter: I think we can close this. They took our feedback on board. Lea had some additional non-blocking

Dan: terrific! closing comment

closed

Comment by @loubrett May 3, 2022 (See Github)

Thanks for all the feedback, I'm going ahead with Peter's suggestion - I've now updated the explainer to reflect this.

Comment by @torgo May 23, 2022 (See Github)

Thanks for the update @loubrett! Based on your feedback we're going to go ahead and close this. We're happy to see this work proceed. Please ensure that it has a destination working group after incubation in WICG.