Open hanguokai opened 2 years ago
I fully support it. However, it seems to me that it should be implemented as a browser-based JS API available for websites as well. The point is that all the problems from the list above are relevant for Favicons.
I think website favicon and extension icon are not exactly the same problem.
Here is a stackoverflow question for website favicon. There are several solution for it. For example, svg favicon with media query, <link>
element with media attribute. At least, there is a no-JS solution for light/dart theme.
But these solutions do not apply to extensions. Extension icons are declared in manifest.json. And there is no window.matchMedia('xxx').addEventListener
in extension service worker. There are also custom theme(extension theme) that can change toolbar color.
Chromium is tracking a similar feature request in issue 893175. A Chromium engineer shared a link to a design doc we were considering in comment 19, but that effort is currently on hold.
@xeenon, @zombie, and @mukul-p, it might be worth taking a look at this and sharing feedback either on the doc or on a related issue.
I see the design doc. It is a static(declarative) way in manifest file. I think it solves 90% of the problems.
I think a runtime API should also be provided to solve dynamic problems, because developers can change icon by setIcon()
method. For example adding two new apis below:
chrome.runtime.getTheme(); // return 'light' or 'dart' or background color
chrome.runtime.onThemeChanged.addListener(theme => changeIt()); // listener for theme changed
We can draw some inspiration from ongoing discussion on how to handle this in PWA manifests, see: https://github.com/w3c/manifest/issues/758 https://github.com/w3c/manifest/issues/975 https://github.com/w3c/image-resource/issues/26
In general, going for a list of icons versus an object, like Mozilla did with theme_icons
and PWA do with icons
will give us more flexibility.
We can go for a syntax like this:
"icons": [{
"src": "/pwa-36.png",
"sizes": "36x36",
"media": "(prefers-color-scheme: dark)"
}, {
"src": "/pwa-adaptive-48.png",
"sizes": "48x48",
"purpose": "toolbar"
}]
Or adding a color_scheme
property. Which can be set to "light", "dark", and potentially "monospace" as many extension developers prefer to blend into the browsers design. This has the added benefit it's clear the browser will choose a dark-mode icon when the background of the browser team is a darker color even tho the OS is not using "dark mode".
Firefox implementation can be seen at e.g. https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/action
For best backwards compatibility, we can consider implementing the theme_icons
property for action
/page_action
/browser_action
as is currently implemented by Firefox:
"action": {
"browser_style": true,
"default_icon": {
"16": "button/geo-16.png",
"32": "button/geo-32.png"
},
"default_title": "Whereami?",
"default_popup": "popup/geo.html",
"theme_icons": [{
"light": "icons/geo-16-light.png",
"dark": "icons/geo-16.png",
"size": 16
}, {
"light": "icons/geo-32-light.png",
"dark": "icons/geo-32.png",
"size": 32
}]
}
default_icon
would continue to work fine. While theme_icons
would take priority over default_icon
if present. light
would be used when light text and icons are needed. For example, with a darker background or with dark mode theme. While dark
would be used for light mode themes.
We can then move forward with more breaking changes in regard to icons for Manifest v4.
light would be used when light text and icons are needed. For example, with a darker background or with dark mode theme. While dark would be used for light mode themes.
I didn't know Firefox's theme_icons before. For me, it's counterintuitive. I prefer dark for icons used in dark theme and light for icons used in light theme.
@hanguokai This would then be something we can fix once drafting MV4.
As for the API to update theme_icons
, we can go for:
browser.action.setThemeIcons([{
"light": "icons/geo-16-light.png",
"dark": "icons/geo-16.png",
"size": 16
}, {
"light": "icons/geo-32-light.png",
"dark": "icons/geo-32.png",
"size": 32
}])
Calling this method would overwrite the theme_icons
(if present) defined in the manifest file. If set to an empty array or null or undefined, resets the themeIcons to what has been defined in the manifest file or otherwise fallback to what is defined in 'default_icon'.
Currently in Firefox, setIcon will overwrite what is defined in theme_icons
. Thus at least for MV2 and MV3 we seem to have to stick to this. This means setIcon would also overwrite setThemeIcons. This is not an issue considering developers can check the presence of setThemeIcons and use that instead of setIcon if present. Naturally setThemeIcons would overwrite the icon set by setIcon.
The theme_icons
key and browser.action.setThemeIcons
sounds good to me for Safari.
Discussion on this issue has been narrowed to the action
API, but the need for having a dark variant is broader than that. E.g. extension icons in chrome://extensions
(Chrome) or about:addons
(Firefox) are not toolbar buttons, but there is still a need to have dark theme support.
For reference, 5 years ago I proposed browser.browserAction.setThemeIcons
in https://bugzilla.mozilla.org/show_bug.cgi?id=1484840
Chromium is tracking a similar feature request in issue 893175. A Chromium engineer shared a link to a design doc we were considering in comment 19, but that effort is currently on hold.
@xeenon, @zombie, and @mukul-p, it might be worth taking a look at this and sharing feedback either on the doc or on a related issue.
We (Mozilla) are going to add support for icons.dark
and icons.light
as well as action.default_icon.dark
and action.default_icon.light
in the manifest file (all versions probably). Here, dark
and light
refer to the current theme color scheme and not the text color like theme_icons
like mentioned in some docs/links above.
As for theme_icons
, we'll likely deprecate the manifest key in MV3+.
any updates on chrome extension support for dark mode icon?
Chrome isn't actively working on this but I don't believe we have any specific things we'd change about the proposal right now. Switching to supportive :)
The title of this issue is specific to browser toolbar icons. Should another issue be created for contextMenus
icons or should this issue be considered in wider sense?
A single context menu item by default uses the icons
manifest key, but Firefox allows to specify per-item icon set, see menus.create()
.
Certainly dark menu background may require inverted colors for icons.
This issue actually focuses on all the places where the icon appears, including:
So I change the title of this issue (remove toolbar)
I know that browser vendors have a lot of backlogs to do and need to understand the priorities of different issues.
Many developers have recently asked this question (link-1, link-2, link-3). In other words, whenever you develop a new extension, you need to design an icon, then you may encounter this problem. Supporting light and dark icons is very fundamental, it should get higher priority.
There is currently no ideal workaround. Except toolbar action icon, developers cannot control icons in other places. Even with the icons on the toolbar, developers can't listen to theme changes very well.
According to my observation, developers use the following workaround to solve it:
This method is not the best effect, nor can it achieve effects like browser built-in icons. But this is the most common way to workaround, so the entire extension store is flooded with icons of this design.
We (Chrome) are currently working on an implementation of the icons.dark
/ icons.light
and action.default_icon.dark
/ action.default_icon.light
keys. We've realised there are a few areas of ambiguity in the proposal:
dark
key but not light
?dark
, light
and top-level size keys?
My current thinking is:
Here is my opinion.
What happens if you specify the dark key but not light?
The browser should give a warning, and use it for both dark and light. To use the dark/light keys, developers should provide two sets of icons, which is developers' obligation.
What happens if you specify dark, light and top-level size keys?
The dark/light keys have higher priority than top-level size keys, so the browser should ignore top-level size keys.
for backwards-compatibility
If old versions of browser can ignore the unknown dark/light keys, developers could provides both dark/light and top-level size keys. Otherwise, developers should only provide one of them, and set "minimum_chrome_version" for the dark/light keys.
We should fallback to the light icons for any theme that isn't dark. What if you are in a mode other than dark or light, which is possible in some cases?
I have no clear idea. Can the browser automatically determine that the current theme is more inclined to the light or dark?
As mentioned during our 2023-12-07 meeting. An extension with icons.dark
or action.default_icon.dark
is not allowed to load in Google Chrome tested in Version 119.0.6045.123 (Official Build) (arm64) (MacOS).
Something to take into consideration is the difference between OS dark mode and the need for an icon which works on a dark or light background. The browser could have a custom theming which would mean the icon needed does not equivalent the OS Dark Mode. This is I believe why the theme_icons
implementation mentions dark and light in reverse. Thus for backwards compatibility I still believe theme_icons
could work well.
At present, this issue is mainly about developers' feedback on functional requirements of extension icons on Dark/Light theme, rather than detailed proposal. And all browsers are supportive of this feature.
So this issue has achieved its goal. Next, I suggest that browsers submit a formal PR as the specification (like other browsers' proposals) to w3c/webextensions/proposals
and discuss the specification details there. @oliverdunk @Rob--W @xeenon
While considering a dark/light icon setting in manifest.json
, it would be beneficial to include other associated aspects of toolbar icon i.e.
Just an idea...
{
"action": {
"theme": {
"light": {
"icons": {
"16": "image/icon.svg",
"32": "image/icon.svg"
},
"badge_background_color": "#ffffff",
"badge_text_color": "#000000"
},
"dark": {
"icons": {
"16": "image/icon-dark.svg",
"32": "image/icon-dark.svg"
},
"badge_background_color": "#000000",
"badge_text_color": "#ffffff"
}
}
}
}
Agreed on the noise in this issue @hanguokai - continuing here for now but agree it might be good to have a new issue once we have a concrete proposal.
One thing that came up in the last meeting was that unfortunately icons.dark
etc. fail to load in current versions of Chrome. This means to adopt those keys extensions would need to bump their minimum_chrome_version
.
We haven't settled on anything yet, but with that in mind we've been discussing a few different options. One that has come up is a new icon_variants
key inspired by (but different to) theme_icons
:
"icon_variants": {
"dark": {
"64": "64_icon_dark.png"
},
"light": {
"64": "64_icon_light.png"
}
},
"action": {
"default_icon": {
"64": "images/64_icon.png"
},
"icon_variants": {
"dark": {
"64": "64_action_dark.png"
},
"light": {
"64": "64_action_light.png"
}
}
}
Does this seem like a reasonable way to have a cross-browser key which is backwards compatible?
There would be a few things to decide about precedence but I think we can figure those out if this seems agreeable.
@oliverdunk that is exactly the API I was expecting to come from this issue. Assuming older browser versions can simply ignore the icon variants without it throwing an error I think this would be the best option.
In terms of precedence I'd suggest the following:
I would like to see a way to determine which of the icons was selected in JavaScript so that programmatically defined icons can also follow the theme setting.
It would perhaps be prudent to also add a high contrast option to the icon variants for improved accessibility.
@oliverdunk one suggestion is to work together with the Web Applications WG on how to best specify this in the manifest. They have some interesting discussions about this: https://github.com/w3c/manifest/issues/1045 https://github.com/w3c/manifest/issues/975
In general it is good not to forget the need for icons which work well on a dark / light background independent of the operating system dark mode due to custom browser theme requirements.
My suggestion is to prioritise a way to set action icons for dark backgrounds programmatically.
@JamesCoyle Instead of allowing the extension to detect which mode is used (dark/light), I would propose setting both when calling action.setIcon
to prevent a bunch of extensions needing to do work when the light/dark mode or theme of a browser changes. Think of something like:
browser.action.setIcon({
imageData: {
16: image16,
32: image32,
},
darkBackground: {
imageData: {
16: image16,
32: image32,
}
}
});
Either using dark
or darkBackground
is up for discussion. Using darkBackground
here to emphasize the above mentioned need for icons which work well on dark backgrounds when in light mode because of custom browser themes.
Since the action button is the main area which has this need. We could allow changing badgeBackgroundColor and badgeTextColor in the calls as well. Think of something like this:
browser.action.setThemeData({
"dark": {
"badgeBackgroundColor": "lightgreen",
"badgeTextColor": "black",
"icon": "dark.svg",
},
"light": {
"badgeBackgroundColor": "green",
"badgeTextColor": "white",
"icon": "light.svg",
}
});
@carlosjeurissen extending setIcon to allow for the icon variants would work for me. I can't currently think of a use-case that wouldn't work with that.
It would be nice if SVG icons simply supported fill="currentColor"
or something similar.
Edit: this currently works thanks to fill="context-fill"
special property, but it only works in official Mozilla extensions, because it's non-standard. The current Mozilla plan is to implement and use CSS linked parameters spec for that.
@phaux I agree, that should work in Safari.
@phaux how about using an env variable for this to provide authors a way to have a fallback in case the browser does not support this feature?
For my use case, I am dynamically creating the browser icon at runtime. In order to accommodate dark and light modes, I draw different styles to a canvas and then set the icon to the canvas contents. An API design which takes as input both images would be better than needing to detect the theme in a offscreen document, but would still require wasted work painting the unused theme's respective canvas.
Preferably media queries would be exposed to service workers, but something like browser.runtime.theme == "light" || "dark"
would also be nice.
Also, notifications are another surface to consider.
An API design which takes as input both images would be better than needing to detect the theme in a offscreen document, but would still require wasted work painting the unused theme's respective canvas.
The tradeoff here is that it means the icons wouldn't be available when the theme first changes, and we couldn't update them at the same time as everything else. I don't think exposing media queries to service workers is off the table but I think we'd be hesitant to encourage doing reactive work based on theme changes, at least in the most common cases :)
Also, notifications are another surface to consider.
For sure!
@oliverdunk Very much agree with having both dark and light icons available so a theme switch can be made is a good one. However I believe exposing additional metadata for the action icon would be very useful in reducing the icons needed to generate and action icons are as pixel perfect as possible. For example, devicePixelRatio is currently not available in serviceWorkers sadly.
Think about a method like chrome.action.getIconSpecs()
returning
{
"size": 16,
"dpi": 2,
"actualSize": 32,
"color_schemes": ["light", "dark"]
}
color_schemes
would give the color schemes the browser supports. This again reduces the amount of icons needing to be generated with imageData.
On the topic of DPR, I just realized that the multiple monitor use case is also something to consider. There can be multiple screens with different icon sizes.
So for a hypothetical function to get the icon size, you would need to return a set or array of icon sizes. You should then be able to use that with the existing size based action.setIcon
, though I haven't tested whether that API handles multiple monitors correctly in browser implementations.
As far as I can tell calculating icon sizes for multiple screens is currently not trivally implemented. On Chrome OS you can calculate the icon size as 16 * DPR as retrieved from chrome.system.display, which is easy enough. However, that API doesn't expose the needed data on other platforms, so you have to fall back to either getScreenDetails on Chromium on Linux/Windows/Mac, which requires a permission prompt, not from the background but from an extension popup or tab. Alternatively on Firefox creating a tab or popup on each display and retrieving DPR data from there, if the browser.windows.create API even allows that, or requiring a global content script injected just to read DPR on other screens.
Should this icon size retrieval topic be filed as a separate issue?
A new issue would be best.
A little related to issue-216. Besides the text color and background color of the BadgeText, the extension icon itself is also a problem to adapt to various themes (Light/Dark/Custom).
Current state, developers can set static extension icon or dynamic change it by
setIcon()
. But: