You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Add support for defining a theme color for both light & dark modes (prefers color scheme) #975
{
"lang": "en",
"short_name": "Resilience",
"name": "Resilient Web Design by Jeremy Keith",
"description": "A web book in seven chapters on the past, present, and future of web design. By Jeremy Keith.",
"background_color": "#5f7995",
"theme_color": "#5f7995"
}
There's not currently any way to express that a certain theme color should be used for light mode, while another is used for dark mode.
In HTML, there's currently a proposal to add support for color schemes by adding a media attribute to the meta tag: whatwg/html#6495
I don't think we can touch "theme_color" as that will break older browsers.
We may want to create a "theme_colors" (plural) property that is an array of objects (so that it's extensible if needed in the future) that would take precedence over "theme_color"
I don't have a strong preference, but I think using the last item in the list that matches (i.e. last pass) is generally easier to understand/follow (it also more closely matches the way it would be written in CSS).
If this is an approach we like, perhaps we could/should do it for "background_color" (i.e. "background_colors") too?
Reacted by Jeremy Wagner, Mehdi Merah, Brandon Bennett, Valentine Briese, intrnl, John, Matthew Halloran, Allen Lantz, Blake Lee, Marek Polakowski and 21 more
I'm in favor of this approach. It leaves existing functionality where it is, and extends the web manifest in a way that allows for existing or future media values should they become applicable in this scenario.
That approach makes sense to me as well – although I might think of it as a default/shorthand, and longhand list of alternates, rather than new and legacy values. That would allow a simpler combination in the short term:
Reacted by Devin Rousso, Jeremy Wagner, Mehdi Merah, fantasai, Theresa O’Connor, Matt Giuca, Jeremy Keith, Brandon Bennett, Sean van Zuidam, Ninh Vũ and 5 more
+1, see my comment on w3c/image-resource#26 where I said "sure it would be great for ImageResources, but we'd also want it for the theme color". @aarongustafson FYI.
We (Google) are thinking about implementing something like this in the near future (~N quarters) so having agreement on the exact format of this field in the manifest would be great.
@mirisuzanne 's proposal sounds good to me. The problem it's trying to solve (not breaking backwards compat with the existing theme_color spec) has echoes of display-override and the solution is similar (have a separate field that overrides the existing field's values with more nuanced information).
Thanks for filing this @jensimmons, It’s been on my backlog for a few weeks.
We discussed this over in #955 as well. I think the piece that’s missing from the above suggestions is that multiple members may need to change based on the color scheme. My original thought was that we introduce a color_schemes member which supports multiple color schemes as defined by CSS. That way it stay in lock-step with that spec as it continues to evolve. So, for example:
I like your first combined syntax, with media-conditions as keys, with nested objects. If we were matching the way CSS works, I would expect last-take-precedence when there are multiple matches - but maybe first-takes-precedence fits the existing scheme better? I don't know.
I like your first combined syntax, with media-conditions as keys, with nested objects.
That’s my preference as well. Not knowing the innards of browser engines, it also feels like it would be faster to process because you wouldn’t have to parse the object to determine whether you need to throw it away.
If we were matching the way CSS works, I would expect last-take-precedence when there are multiple matches - but maybe first-takes-precedence fits the existing scheme better? I don't know.
This is the confusing piece, I agree. So we have 2 conflicting paths for this stuff: In CSS proximity wins whereas in things like audio, video, and picture the first match wins (even with media in play). Again, not knowing the browser innards well and going purely by the processing algorithms we define in the spec, I believe the first match winning is less computationally expensive overall, which is why I tend to lean in that direction.
I’d love someone with knowledge of the perf cost to weigh in here and set me straight if I’m incorrect.
Re: adding theme_colors to live alongside theme_color, and perhaps extending that idea to add background_colors to live alongside background_color...
This is the kind of thing the CSSWG always avoids. It's very confusing for developers to have remember whether or not there's an 's' at the end — and that the version with the 's' works differently than the one without. This is especially true for folks who don't speak English fluently or at all, which is an incredible number of developers.
An entirely different name is much better, like color_schemes or color_overrides. This is something that people can learn & understand completely separate from the original mechanism for theme color... and eventually let theme_color fade away as something the industry ignores when teaching or doing web development in the future.
Reacted by Aaron Gustafson, Miriam Suzanne, Dean Jackson, Florian Rivoal, Brandon Bennett and Muhammad Jamaluddin
Hmmm..., we'd probably want to just generalize the overrides... and now I've changed my opinion about the property names, as it's clear what it's doing...
Reacted by Thomas Steiner, Aaron Gustafson, Brandon Bennett, Judah Gabriel Himango, Lance Gliser, Aloïs de Gouvello, Evelyn Hathaway, Park Hee Chan and Matthew Kimball-Cobbs
@christianliebel raised a bunch of good points about src and backwards compatibility - our conclusions:
Because we skip icon parsing if ‘src’ is not present (confirmed chrome, webkit gecko), we can use that to ensure we don’t break compatibility
Options that seemed best right now
Fully move to the webextensions format, % needing them / us to specify how the ‘any’ size is chosen (first vs fallback). We also need non-square sizes for screenshots.
This is a BIG spec change. We would formalize the new format, and have the legacy format ‘parse’ into the new format
Code change definitely, but likely not huge. Not a new OS integration
Definitely devrel effort
Support the webextensions format but ‘parse’ it into the old format. This, for devs, is the same as the first option, but for us is less work, as the spec change is smaller, and the code changes are smaller
Otherwise, doing only color_scheme addition has backwards compatibility risk UNLESS we can confirm that Gecko & WebKit will always choose the ‘last’ appropriate icon from the list - this is what Chrome does. So devs who add color scheme icons would need to make sure that it is ‘first’ in the list, and they have equivalent icon later in the list for the legacy impls to choose
I18n might be better if the languages are separate, so we could do the above two only for color_scheme, and keep the icons and icons_localized situation. This is easier for translators, but might be harder for devs to know exactly what icon is chosen.
Other options seem kinda sad, like fully denormalized
With our flat list, we have to look at all of the things at the same time and it's confusing for developers how this works, wereas the webextensions version allows us to look for a matching entry first, and then choose an appropriate size. So, for example, there could be only one entry for "dark_color_scheme", and then all of that same icon will be in that entry. In the manifest icon list, each icon is it's own icon entry, so each would have to have that scheme.
Our method works but it's kinda hard to read and the algorithm is weirder. The schema is nicer to understand "first, choose the entry that matches your NON-size constraints. Then, choose an icon size that you want"
The main question for dev-facing changes here is - do we use a new format, or an old format with a scheme (and maybe lang). I guess localization is a question here too. Do others have thoughts? Favorites? I'll throw out that my favorite is maybe option ii), where we do the new format, and the spec turns into the old format to make it easier to initially do.
The only extra thing we need to do probably is specify the order in which the filters are supplied. e.g.:
If we are french and also dark mode, we can't get both of those constraints. So which constraint do we drop first? We would jsut want to order them, likely, 1. color_schemes, 2. lang. So we would choose the default dark mode icon, even though it is not french.
Reflecting after manifest meeting with @marcoscaceres yesterday:
The most important things to do dark mode / light mode here are theme color and background color.
Icon localization + dark mode / light mode seems probably rare, and I would actually say that it would require some UX changes in Chrome for us to allow to both a light mode and a dark mode icon (as we would need to present them to the user, both). However, I could easily see this just happening one time when the dark mode / light mode preferences changes, where we present it like an update but with better language
e.g. "This app has support for a dark/light mode icon. Please approve the icon change for dark/light mode."
<approve / ignore / uninstall / learn more>
So - I think my proposal is this, which IMO solves this nicely in a way that seems readable and allows us to hopefully unify with WebExtensions. It adds the 'type' and other attributes we were using before, but has the new per-size grouping.
It adds WxH parsing for icon size
It formalizes the choosing algorithm, and makes a static constraint fallback order (happy to hear feedback on this)
Algorithm for a user agent to choose an icon group:
User agent then specifies:
the following 3 constraints, ordered by importance:
Color Scheme <dark, light>
Purpose <any, maskable, monochrome, unspecified>
Language
User agent first removes all icon groups / entries that are fully not supported
e.g. on desktop we would remove all 'monochrome' groups, as that is not supported, only on Android. Windows doesn't do masking yet, so it would also remove 'maskable'.
same with 'platform' for screenshots.
user agents can also probably have a maximum size too - e.g. nothing larger than 2096
probably remove entries with no icon paths too (or those just don't parse)
found_icon_group = null
Loop through all icon entries:
If the entry satisfies all constraints, set found_icon_group to the group
If found_icon_group == null
exit if no constrains left with null
(This might happen if user agent doesn't require a basic 'any' icon for installation - usually they seem to choose the favicon for this, so for those user agents, the saved favicon can be the fallback)
remove the last constraint from the list, and GOTO the loop again 😛
This matches our current implementation for choosing icons for a platform given a purpose
Then, algorithm for user agent to choose an icon from a group:
User agent specifies an ideal size, WxH
any_size_icon_path = null
closest_larger_icon = null
closest_smaller_icon = null
loop through sizes in the icon group
if the size matches the ideal size, return that.
if the size is larger, set it to closest_larger_icon (do standard distance stuff if there was one already found)
if the size is smaller, set it to closest_smaller_icon (do standard distance stuff if there was one already found)
if the size matches any, set any_size_icon_path to the icon path
if any_size_icon_path != null, then return any_size_icon_path
if closest_larger_icon != null, then return closest_larger_icon
if closest_smaller_icon != null, then return closest_smaller_icon
return null
Using the above algorithms, examples of queries for groups with
light, maskable, french -> *-size-fr-mask.png - found all!
light, maskable, english -> *-size.png (not maskable, preferred light)
dark, maskable, french -> *-size-dark.png (not french or maskable, preferred dark)
The existing constraint fallback is what seems correct to me, where the light/dark is the most jarring / should get right, then any vs maskable for platform support, then language. But I'm happy to have that order changed, or... I guess say the user agent can specify. But I think that it's better to have this be extra predictable for devs. We can even make an easy demo site for people to understand, given a manifest, what is chosen when.
@dmurph A thing to be careful of is that locales ( == language tags) have fallback. For example, fr-FR => fr => root (default resources). This is another reason why we like language maps: the language tag is visible on the outside, making it easier for people managing translations or variations to spot/organize the translations.
Anything that's defined as UX should be localizable. Some things, such as icons, might only be localized in a few languages. Other things might be localized nearly all the time. The mechanism for localization should be orthogonal to the "mechanical" aspects of selecting the correct resource (size/orientation/etc.) and there should always be a clear default resource that the developer writes (or is required to write) and that is used when locale-specific values are not provided or not available for a given request.
we change the key to a space-separated list of language tags
This could make things complicated, since the list must be parsed into tokens which are then prefix compared to the requested locale. In practice, localizers are more likely to want separate entries anyway. The rest of your example is good, from the point of view that there is a clear "source" (icons) for all of the icons_localized that acts as the root locale entry. The localized icons only override the source when provided.
@aphillips I'm assuming that is solved by simply allowing the language constraint matching to do that fallback fr-FR => fr when it's looking for a language constraint match. If that isn't the case, let me know, or what would need to change.
And yes, a con of this approach is that, say, the french translations are in multiple entries. But they can still be in the same area in the list (but the dev would have to organize that)
If that is an unacceptable con, the we can keep the existing *_localized.
And then to clarify what you said for Marcos's suggestion - it's just that it doesn't force the separation, so it might be confusing? It would still seem to work though, right? "fr-BE fr-CA" could be a dict key, and then a separate "fr" dict key could be there - it's just a shortcut to make stuff shorter if people want to.
@marcoscaceres@aphillips using space separated list of language tags like you are proposing looks quite elegant and makes the yandex case more compelling. If duplicate languages are present as a result of this syntax (ie "ru be" and "ru"), implementations can favour the shortest property ("ru"). Unless there is other subtags (ie "zh-Hans zh-Hant" would win over "zh" if the preferred script is Hans or Hant. It would only make parsing a bit more complicated. Is this "shorthand" something we would want to add to the text version of _localized as well?
As for icons specifically, it could make the hybrid (option iv. in @dmurph#975 (comment)) less verbose in the yandex case.
Unlike for normal localized text, localized resources still need the resource files to be put in the right place. This often still involves developers. So this aspect may not be as important as is the case for localized text members.
The rest of your example is good, from the point of view that there is a clear "source" (icons) for all of the icons_localized that acts as the root locale entry. The localized icons only override the source when provided.
If the locale is "fr", it would result in [{a},{b},{c}] ?
(ignoring the fr-CA override as that is more specific than fr?)
and if the locale is "fr-CA", it would result in [{d}] ?
(completely discarding any icons in the main icons member, as there is a localized override?)
Current icons order for equal options
@dmurph you mentioned Chromium always picks the last one. While it seems to generally mostly uses the last one. I found one case where it chooses the first one. This happens in the "install app" submenu. See screenshot:
Click to expand screenshot
Screenshots
@dmurph reading in the meeting notes a reference to screenshots. While the webExtensions syntax seems very useful for icons, as for icons, implementations always have to choose ONE icon. We may not want to adopt this syntax for screenshots. Unlike icons, the screenshots member has already meaning to the order. The first item in the list is the first one you want to be displayed. Merging this with the constraints order seems to result in an order mismatch.
While using a different syntax for screenshots vs icons sounds counter intuitive. They are already different beasts. Screenshots have a specific order, with properties like form_factor which icons do not have. Screenshots on the other hand do not have the purpose property.
Many publishers include both light and dark mode screenshots to inform user candidates the app supports both light and dark mode, and how each of them looks like. For screenshots, the color_scheme is always a single value. It could be seen as annotation similar to the current form_factor screenshots property. It is then up to the store or installation prompt to decide whether or not to display both light/dark screenshots.
Unlike icons, for screenshots, having browsers ignore the color_scheme property seems to not have any significant impact.
In a similar fashion, the languages for screenshots are also always a single value. When it comes to screenshots, we can either introduce screenshots_localized similar to the icons_localized, or add annotations to each screenshot in the form of a lang: "en" property. Appending each localized version after the default screenshots would allow implementations to filter-out specific languages while older implementations would simply append them to the list of screenshots. (And hopefully do not download and render all screenshots in this list).
Having all screenshots together without using a separate color_scheme_dark.screenshots bucket would allow authors to express screenshot order with mixed light/dark modes in case stores do not filter either of them. (which is 100% now).
"If we are french and also dark mode, we can't get both of those constraints. So which constraint do we drop first? We would jsut want to order them, likely, 1. color_schemes, 2. lang. So we would choose the default dark mode icon, even though it is not french."
There are several approaches here. We can leave the order up to the implementations (messy/unreliable), spec out the exact order (like you mention) OR, we stick to the webExtensions logic. In which the order of the groups determines which constraints take precedence. This basically outsources the precedence responsibility away from the spec/implementation to the manifest author. The latter actually requires the icon-sizes to be grouped like this.
If one of the icon groups contains properties (ie potential constraints) the implementation does not support / understand. The whole icon group should be skipped and the implementation should look at the next object. This allows future extensions with additional constraints without backwards compatibility risks. For example, a developer may prefer svg over webp over png, and specifies them in the type. If a browser does not understand the type, it goes to the next block. Say a new constraint like high contrast were to be introduced, it will safely be ignored by old implementations without any side effects.
If we however let the browser determine the precedence, as specified by @dmurph#975 (comment). We can use the same logic for screenshots. For screenshots specifically, we could even re-use the src/sizes as I don't think showing all screenshots is a bad thing see above. On the other hand, adding multiple sizes in the same group could indicate it is the same view in different screen-sizes.
Just keep in mind currently webExtensions are designed to make the author determine the order. However given icon_variants is not widespread yet, the consequences of changing this behaviour seems low. Especially since webkit currently does not discard icon groups with unknown properties (see w3c/webextensions#229 (comment)).
@dmurph the reasoning of dropping (unsupported) constraints when no match could be found sounds very compelling! We would need to figure out what properties to discard first.
Yes, it's definitely different with wanting multiple and the order mattering more. I believe for screenshots the parts of the 'algorithm' I had above would mostly be executing the pre-filter part, to remove all of the wrong platform stuff, and then just return them all after that. So - same 'algorithm' but the user agent would never specify a constraint list kinda (except for lang) - as screenshots don't have purpose or color scheme.
Regarding constraints:
I agree that there is an initial filter step, then a constraint search step. Definitely the algorithm could return a list if we want more than one, instead of just one. That could be a different mode. That helps for screenshots.
For 'constraints not known'.... I 'think' that is OK? I guess for supporting backwards compatibility, if a new constraint is added... yeah you would need to have entries without that new constraint anyways.... so that seems fine....
And yes - to me it seems like this can be a statically defined list, and IMO in the real world:
if there is a problem with this precidence (e.g. the dark-maskable-french example above where it used the non-french icon due to no french icon specified that was dark), the developer can simply just add the french-maskable-dark icon and fix it.
I am interested in the opinion of @christianliebel for incorporating the 'lang' into the icons vs separate dicts per lang, like we currently have. e.g. is that better dev ergonomics, especially if we change it so that we can specify multiple lang keys in the dict key ("en": {}, "en-UK en-CA": {}, ...) to help with duplication.
For 'constraints not known'.... I 'think' that is OK? I guess for supporting backwards compatibility, if a new constraint is added... yeah you would need to have entries without that new constraint anyways.... so that seems fine....
Could you clarify what you mean with that is OK? Do you agree the icon group should be ignored in the initial search? (Unless the final result is null/0). Indeed for backwards compatibility, you would have to add entries without this constraint/property. However we should specify what should happen when unknown/unsupported properties/values are encountered.
if there is a problem with this precidence (e.g. the dark-maskable-french example above where it used the non-french icon due to no french icon specified that was dark), the developer can simply just add the french-maskable-dark icon and fix it.
In that case we are back to the duplication problem. Yet only if the intended precedence order of the author is different than what we may specify. The precedence author-defined order would solve this and defer the responsibility to the author. (saving us the need to spec this out).
A hybrid could be to use the order in screenshots to determine the gallery order and use the order in icons to determine the precedence order (given you can only select one icon). This may not be as much of a conflict as we may think.
One more note on dark icons: for webExtensions, icons are mostly transparent. Dark icons are also used in light mode when a browser theme is used with a dark background (like olive green for example). It uses it as clue as what background works well. However seems with the introduction of the liquid glass dark app icons. "dark mode icons" means more than icons working well on a dark background. Seems for maskable icons, sticking with the system dark mode makes most sense. While for the transparent icons, looking at the background seems to make more sense. Yet this is probably up for the implementation to determine.
Just to clarify how the author-defined precedence order algorithm would work:
look for the first icon group
for each condition in the object:
2.1) check if the condition category name (like color_schemes) is understood, else MUST move to the next object
2.2) if the condition is an empty array. move to the next object.
2.3) check if the requested condition is matching one of the values specified in the condition, if not, move to the next object. Unknown condition values are ignored as long as one is matched, allowing future extensions.
once an icon group has all matching conditions (or the group specifies no conditions). Take all icon size declarations and use the one which is closest to the requested icon size similar to the existing algorithm we have.
This could be further refined by progressively removing constraints when reaching the end of the list.
Spec/implementation defined-precedence
@dmurph If we conclude deferring the order precedence to the author by them ordering it properly in the icons object is giving them too much responsibility. We may be able to resolve the approach by allowing developers to specify the "any" value for all the constraints.
With this approach, implementations would follow something similar to the algorithm @dmurph described. With a spec-defined order of precedence. Yet by adding "any" as value for some of the constraints, developers can opt-in to the author-defined order (the current web-extension icon_variants logic). In a way working a bit similar to css selector specificity. ie, using ".class.class" vs ".class". This basically assigns a meaning towards being very explicit and puts the icon groups in the same importance. If all icon groups have the same amount of constraints, (and using the any matches at times), authors can basically opt-in to the author defined order. This replaces duplication with "any" annotations.
This way there is no need for duplication while being more forgiving to inconsiderate / careless authors/developers and generally be more predictable. It seems it could be the best of both worlds, and allowing alignment with screenshots handling. While unpredictable, this would potentially allow implementations to choose their own precedence at times when they find it important. Still this feels more like a patch than anything else. Going for author-defined precedence order could save us a lot of complications for spec and implementations.
Ah.... author defined precedence - Sorry I missed that part. That's definitely another option. The main difficulty there, I believe, is merging the old and new icon types in one list, as the old list's behavior is the opposite for Chromium - we use the 'last' appropriate one we find, not the first. I don't think it's impossible to change this behavior - we would want to likely inspect the all of the manifests of the top X installed PWA sites to make sure that this wouldn't cause problems - but yeah. Another change.
There are sooooo many ideas here, I worry about this conversation never ending.
What can we agree on that will have impact? what about just the theme & background colors?
@marcoscaceres had this suggestion above I think - What do we all think about this? This seems fine to me:
Activity
malchata commentedon May 4, 2021
One approach that sounds good to me would be to overload
"theme_color"to accept either a string (the current behavior), or a nested object like so:Not sure if this approach conflicts with existing functionality in any way, but it's the first approach that came to mind.
dcrousso commentedon May 4, 2021
I don't think we can touch
"theme_color"as that will break older browsers.We may want to create a
"theme_colors"(plural) property that is an array of objects (so that it's extensible if needed in the future) that would take precedence over"theme_color"I don't have a strong preference, but I think using the last item in the list that matches (i.e. last pass) is generally easier to understand/follow (it also more closely matches the way it would be written in CSS).
If this is an approach we like, perhaps we could/should do it for
"background_color"(i.e."background_colors") too?malchata commentedon May 4, 2021
I'm in favor of this approach. It leaves existing functionality where it is, and extends the web manifest in a way that allows for existing or future
mediavalues should they become applicable in this scenario.mirisuzanne commentedon May 4, 2021
That approach makes sense to me as well – although I might think of it as a default/shorthand, and longhand list of alternates, rather than new and legacy values. That would allow a simpler combination in the short term:
Authors could also choose to provide only the default:
Or (down the road) move to only using the longhand:
tomayac commentedon May 5, 2021
Also see w3c/image-resource#26 where the same question is discussed in the context of
ImageResourceas used by Web Application Manifest.mgiuca commentedon May 6, 2021
+1, see my comment on w3c/image-resource#26 where I said "sure it would be great for ImageResources, but we'd also want it for the theme color". @aarongustafson FYI.
We (Google) are thinking about implementing something like this in the near future (~N quarters) so having agreement on the exact format of this field in the manifest would be great.
@mirisuzanne 's proposal sounds good to me. The problem it's trying to solve (not breaking backwards compat with the existing
theme_colorspec) has echoes ofdisplay-overrideand the solution is similar (have a separate field that overrides the existing field's values with more nuanced information).aarongustafson commentedon May 7, 2021
Thanks for filing this @jensimmons, It’s been on my backlog for a few weeks.
We discussed this over in #955 as well. I think the piece that’s missing from the above suggestions is that multiple members may need to change based on the color scheme. My original thought was that we introduce a
color_schemesmember which supports multiple color schemes as defined by CSS. That way it stay in lock-step with that spec as it continues to evolve. So, for example:Of course there’s also
prefers_contrastandforced_colors, which we may want to consider in any solution. Perhaps, combining this idea with @mirisuzanne’s:or
In terms of processing, I’m not sure which would be faster to compute. We’d probably also want the first match to win if there are multiple matches.
Thoughts?
mirisuzanne commentedon May 7, 2021
I like your first combined syntax, with media-conditions as keys, with nested objects. If we were matching the way CSS works, I would expect last-take-precedence when there are multiple matches - but maybe first-takes-precedence fits the existing scheme better? I don't know.
aarongustafson commentedon May 7, 2021
That’s my preference as well. Not knowing the innards of browser engines, it also feels like it would be faster to process because you wouldn’t have to parse the object to determine whether you need to throw it away.
This is the confusing piece, I agree. So we have 2 conflicting paths for this stuff: In CSS proximity wins whereas in things like
audio,video, andpicturethe first match wins (even withmediain play). Again, not knowing the browser innards well and going purely by the processing algorithms we define in the spec, I believe the first match winning is less computationally expensive overall, which is why I tend to lean in that direction.I’d love someone with knowledge of the perf cost to weigh in here and set me straight if I’m incorrect.
conde2 commentedon May 12, 2021
1+ for this one, would like to see this in webmanifest
jensimmons commentedon May 20, 2021
Re: adding
theme_colorsto live alongsidetheme_color, and perhaps extending that idea to addbackground_colorsto live alongsidebackground_color...This is the kind of thing the CSSWG always avoids. It's very confusing for developers to have remember whether or not there's an 's' at the end — and that the version with the 's' works differently than the one without. This is especially true for folks who don't speak English fluently or at all, which is an incredible number of developers.
An entirely different name is much better, like
color_schemesorcolor_overrides. This is something that people can learn & understand completely separate from the original mechanism for theme color... and eventually lettheme_colorfade away as something the industry ignores when teaching or doing web development in the future.aarongustafson commentedon May 24, 2021
100% agree with @jensimmons on the naming stuff above.
Could @mgiuca @marcoscaceres @tomayac @rayankans and/or anyone else who works on internals weigh in on any perf differences between the options I outlined above.
marcoscaceres commentedon Jun 1, 2021
I can't see any perf differences, but I'd be inclined to go with:
Just from an object creation POV. I'm personally not a huge fan of property names having a dual role.
However, we will need to work out what to do when multiple media queries/features match. Last wins? first wins? Most specific wins?
marcoscaceres commentedon Jun 1, 2021
Hmmm..., we'd probably want to just generalize the overrides... and now I've changed my opinion about the property names, as it's clear what it's doing...
116 remaining items
dmurph commentedon Feb 5, 2026
Discussion at US/EU manifest spec meeting here.
@christianliebel raised a bunch of good points about src and backwards compatibility - our conclusions:
Interested in the thoughts of others.
dmurph commentedon Feb 5, 2026
from meeting with @mkruisselbrink:
Our method works but it's kinda hard to read and the algorithm is weirder. The schema is nicer to understand "first, choose the entry that matches your NON-size constraints. Then, choose an icon size that you want"
The main question for dev-facing changes here is - do we use a new format, or an old format with a scheme (and maybe lang). I guess localization is a question here too. Do others have thoughts? Favorites? I'll throw out that my favorite is maybe option ii), where we do the new format, and the spec turns into the old format to make it easier to initially do.
The only extra thing we need to do probably is specify the order in which the filters are supplied. e.g.:
If we are french and also dark mode, we can't get both of those constraints. So which constraint do we drop first? We would jsut want to order them, likely, 1. color_schemes, 2. lang. So we would choose the default dark mode icon, even though it is not french.
marcoscaceres commentedon Feb 6, 2026
@carlosjeurissen, I guess one could achieve the same thing if we change the key to a space-separated list of language tags:
Doesn't that pretty much achieve the same thing? And has that nice copy/pasta 🍝 quality that @aphillips mentioned.
dmurph commentedon Feb 6, 2026
Reflecting after manifest meeting with @marcoscaceres yesterday:
So - I think my proposal is this, which IMO solves this nicely in a way that seems readable and allows us to hopefully unify with WebExtensions. It adds the 'type' and other attributes we were using before, but has the new per-size grouping.
"icons":
{ "32": "32-size-fr.png", "64": "64-size-fr.png", "type": "image/png", "lang": "fr", "purpose": "any" }, { "32": "32-size-fr-mask.png", "64": "64-size-fr-mask.png", "type": "image/png", "lang": "fr", "purpose": "maskable" }, { "32": "32-size.png", "64": "64-size.png", "type": "image/png", "purpose": "any" }, { "32": "32-size-dark.png", "64": "64-size-dark.png", "type": "image/png", "color-scheme": "dark", "purpose": "any" }, { "32": "32-size-dark-maskable.png", "64": "64-size-dark-maskable.png", "type": "image/png", "color-scheme": "dark", "purpose": "maskable" },"screenshots":
{ "1280x720": "screenshots/home.webp", "type": "image/webp", "form_factor": "wide", "label": "Home screen showing main navigation and featured content" }, { "1280x720": "screenshots/dashboard.webp", "type": "image/webp", "platform": "ios", "label": "Dashboard view displaying key metrics" }Algorithm for a user agent to choose an icon group:
found_icon_group = nullfound_icon_groupto the groupfound_icon_group == nullnullThis matches our current implementation for choosing icons for a platform given a purpose
Then, algorithm for user agent to choose an icon from a group:
any_size_icon_path = nullclosest_larger_icon = nullclosest_smaller_icon = nullclosest_larger_icon(do standard distance stuff if there was one already found)closest_smaller_icon(do standard distance stuff if there was one already found)any, setany_size_icon_pathto the icon pathany_size_icon_path != null, then returnany_size_icon_pathclosest_larger_icon != null, then returnclosest_larger_iconclosest_smaller_icon != null, then returnclosest_smaller_iconnullUsing the above algorithms, examples of queries for groups with
*-size-fr-mask.png- found all!*-size.png(not maskable, preferred light)*-size-dark.png(not french or maskable, preferred dark)The existing constraint fallback is what seems correct to me, where the light/dark is the most jarring / should get right, then any vs maskable for platform support, then language. But I'm happy to have that order changed, or... I guess say the user agent can specify. But I think that it's better to have this be extra predictable for devs. We can even make an easy demo site for people to understand, given a manifest, what is chosen when.
aphillips commentedon Feb 6, 2026
@dmurph A thing to be careful of is that locales ( == language tags) have fallback. For example,
fr-FR=>fr=>root(default resources). This is another reason why we like language maps: the language tag is visible on the outside, making it easier for people managing translations or variations to spot/organize the translations.Anything that's defined as UX should be localizable. Some things, such as icons, might only be localized in a few languages. Other things might be localized nearly all the time. The mechanism for localization should be orthogonal to the "mechanical" aspects of selecting the correct resource (size/orientation/etc.) and there should always be a clear default resource that the developer writes (or is required to write) and that is used when locale-specific values are not provided or not available for a given request.
@marcoscaceres suggests that:
This could make things complicated, since the list must be parsed into tokens which are then prefix compared to the requested locale. In practice, localizers are more likely to want separate entries anyway. The rest of your example is good, from the point of view that there is a clear "source" (
icons) for all of theicons_localizedthat acts as therootlocale entry. The localized icons only override the source when provided.dmurph commentedon Feb 6, 2026
@aphillips I'm assuming that is solved by simply allowing the language constraint matching to do that fallback
fr-FR=>frwhen it's looking for a language constraint match. If that isn't the case, let me know, or what would need to change.And yes, a con of this approach is that, say, the french translations are in multiple entries. But they can still be in the same area in the list (but the dev would have to organize that)
If that is an unacceptable con, the we can keep the existing *_localized.
And then to clarify what you said for Marcos's suggestion - it's just that it doesn't force the separation, so it might be confusing? It would still seem to work though, right?
"fr-BE fr-CA"could be a dict key, and then a separate"fr"dict key could be there - it's just a shortcut to make stuff shorter if people want to.carlosjeurissen commentedon Feb 6, 2026
icons_localized["ru be uk"]@marcoscaceres @aphillips using space separated list of language tags like you are proposing looks quite elegant and makes the yandex case more compelling. If duplicate languages are present as a result of this syntax (ie "ru be" and "ru"), implementations can favour the shortest property ("ru"). Unless there is other subtags (ie "zh-Hans zh-Hant" would win over "zh" if the preferred script is Hans or Hant. It would only make parsing a bit more complicated. Is this "shorthand" something we would want to add to the text version of
_localizedas well?As for icons specifically, it could make the hybrid (option iv. in @dmurph #975 (comment)) less verbose in the yandex case.
Unlike for normal localized text, localized resources still need the resource files to be put in the right place. This often still involves developers. So this aspect may not be as important as is the case for localized text members.
@aphillips mentioned:
Just to clarify, given the following syntax:
{ "icons": [{a},{b},{c}], "icons_localized": { "fr-CA": [{d}] } }If the locale is "fr", it would result in [{a},{b},{c}] ?
(ignoring the
fr-CAoverride as that is more specific thanfr?)and if the locale is "fr-CA", it would result in [{d}] ?
(completely discarding any icons in the main icons member, as there is a localized override?)
Current icons order for equal options
@dmurph you mentioned Chromium always picks the last one. While it seems to generally mostly uses the last one. I found one case where it chooses the first one. This happens in the "install app" submenu. See screenshot:
Click to expand screenshot
Screenshots
@dmurph reading in the meeting notes a reference to screenshots. While the webExtensions syntax seems very useful for icons, as for icons, implementations always have to choose ONE icon. We may not want to adopt this syntax for screenshots. Unlike icons, the screenshots member has already meaning to the order. The first item in the list is the first one you want to be displayed. Merging this with the constraints order seems to result in an order mismatch.
While using a different syntax for screenshots vs icons sounds counter intuitive. They are already different beasts. Screenshots have a specific order, with properties like
form_factorwhich icons do not have. Screenshots on the other hand do not have thepurposeproperty.Many publishers include both light and dark mode screenshots to inform user candidates the app supports both light and dark mode, and how each of them looks like. For screenshots, the
color_schemeis always a single value. It could be seen as annotation similar to the currentform_factorscreenshots property. It is then up to the store or installation prompt to decide whether or not to display both light/dark screenshots.Unlike icons, for screenshots, having browsers ignore the
color_schemeproperty seems to not have any significant impact.In a similar fashion, the languages for screenshots are also always a single value. When it comes to screenshots, we can either introduce
screenshots_localizedsimilar to theicons_localized, or add annotations to each screenshot in the form of alang: "en"property. Appending each localized version after the default screenshots would allow implementations to filter-out specific languages while older implementations would simply append them to the list of screenshots. (And hopefully do not download and render all screenshots in this list).Having all screenshots together without using a separate
color_scheme_dark.screenshotsbucket would allow authors to express screenshot order with mixed light/dark modes in case stores do not filter either of them. (which is 100% now).Constraints precedence
@dmurph mentioned:
If one of the icon groups contains properties (ie potential constraints) the implementation does not support / understand. The whole icon group should be skipped and the implementation should look at the next object. This allows future extensions with additional constraints without backwards compatibility risks. For example, a developer may prefer svg over webp over png, and specifies them in the type. If a browser does not understand the type, it goes to the next block. Say a new constraint like high contrast were to be introduced, it will safely be ignored by old implementations without any side effects.
If we however let the browser determine the precedence, as specified by @dmurph #975 (comment). We can use the same logic for screenshots. For screenshots specifically, we could even re-use the src/sizes as I don't think showing all screenshots is a bad thing see above. On the other hand, adding multiple sizes in the same group could indicate it is the same view in different screen-sizes.
Just keep in mind currently webExtensions are designed to make the author determine the order. However given icon_variants is not widespread yet, the consequences of changing this behaviour seems low. Especially since webkit currently does not discard icon groups with unknown properties (see w3c/webextensions#229 (comment)).
@dmurph the reasoning of dropping (unsupported) constraints when no match could be found sounds very compelling! We would need to figure out what properties to discard first.
dmurph commentedon Feb 6, 2026
Regarding screenshots:
Regarding constraints:
I am interested in the opinion of @christianliebel for incorporating the 'lang' into the icons vs separate dicts per lang, like we currently have. e.g. is that better dev ergonomics, especially if we change it so that we can specify multiple lang keys in the dict key (
"en": {}, "en-UK en-CA": {}, ...) to help with duplication.carlosjeurissen commentedon Feb 6, 2026
@dmurph mentioned:
Could you clarify what you mean with that is OK? Do you agree the icon group should be ignored in the initial search? (Unless the final result is null/0). Indeed for backwards compatibility, you would have to add entries without this constraint/property. However we should specify what should happen when unknown/unsupported properties/values are encountered.
In that case we are back to the duplication problem. Yet only if the intended precedence order of the author is different than what we may specify. The precedence author-defined order would solve this and defer the responsibility to the author. (saving us the need to spec this out).
A hybrid could be to use the order in screenshots to determine the gallery order and use the order in icons to determine the precedence order (given you can only select one icon). This may not be as much of a conflict as we may think.
One more note on dark icons: for webExtensions, icons are mostly transparent. Dark icons are also used in light mode when a browser theme is used with a dark background (like olive green for example). It uses it as clue as what background works well. However seems with the introduction of the liquid glass dark app icons. "dark mode icons" means more than icons working well on a dark background. Seems for maskable icons, sticking with the system dark mode makes most sense. While for the transparent icons, looking at the background seems to make more sense. Yet this is probably up for the implementation to determine.
carlosjeurissen commentedon Feb 7, 2026
Author defined-precedence
Just to clarify how the author-defined precedence order algorithm would work:
2.1) check if the condition category name (like color_schemes) is understood, else MUST move to the next object
2.2) if the condition is an empty array. move to the next object.
2.3) check if the requested condition is matching one of the values specified in the condition, if not, move to the next object. Unknown condition values are ignored as long as one is matched, allowing future extensions.
This could be further refined by progressively removing constraints when reaching the end of the list.
Spec/implementation defined-precedence
@dmurph If we conclude deferring the order precedence to the author by them ordering it properly in the icons object is giving them too much responsibility. We may be able to resolve the approach by allowing developers to specify the "any" value for all the constraints.
With this approach, implementations would follow something similar to the algorithm @dmurph described. With a spec-defined order of precedence. Yet by adding "any" as value for some of the constraints, developers can opt-in to the author-defined order (the current web-extension icon_variants logic). In a way working a bit similar to css selector specificity. ie, using ".class.class" vs ".class". This basically assigns a meaning towards being very explicit and puts the icon groups in the same importance. If all icon groups have the same amount of constraints, (and using the any matches at times), authors can basically opt-in to the author defined order. This replaces duplication with "any" annotations.
In your example.
[{ "512": "fr-512.png", "192": "fr-192.png", "32": "fr-32.png", "lang": ["fr"] }, { "512": "dark-512.png", "192": "dark-192.png", "32": "dark-32.png", "color_schemes": ["dark"] }]With your algorithm,
color_schemestakes precedence over "lang". Developers could opt-in to author-defined order by changing it to:[{ "512": "fr-512.png", "192": "fr-192.png", "32": "fr-32.png", "lang": ["fr"], "color_schemes": ["any"] }, { "512": "dark-512.png", "192": "dark-192.png", "32": "dark-32.png", "lang": ["any"], "color_schemes": ["dark"] }]This way there is no need for duplication while being more forgiving to inconsiderate / careless authors/developers and generally be more predictable. It seems it could be the best of both worlds, and allowing alignment with screenshots handling. While unpredictable, this would potentially allow implementations to choose their own precedence at times when they find it important. Still this feels more like a patch than anything else. Going for author-defined precedence order could save us a lot of complications for spec and implementations.
dmurph commentedon Feb 9, 2026
Ah.... author defined precedence - Sorry I missed that part. That's definitely another option. The main difficulty there, I believe, is merging the old and new icon types in one list, as the old list's behavior is the opposite for Chromium - we use the 'last' appropriate one we find, not the first. I don't think it's impossible to change this behavior - we would want to likely inspect the all of the manifests of the top X installed PWA sites to make sure that this wouldn't cause problems - but yeah. Another change.
There are sooooo many ideas here, I worry about this conversation never ending.
What can we agree on that will have impact? what about just the theme & background colors?
@marcoscaceres had this suggestion above I think - What do we all think about this? This seems fine to me:
Maybe we can agree on this part, and move the icon discussion to another thread?
christianliebel commentedon Feb 10, 2026
I would agree to the color part. Here’s a PR that only introduces dark theme support for colors: #1207
Wood as the default theme; the chrome color always matches the page b…