Summary
Feature to enable developers to enhance extension icon visibility in dark mode.
Document Metadata
Author: solomonkinard
Sponsoring Browser: Chromium
Contributors: oliverdunk, xeenon, carlosjeurissen, hanguokai, dotproto
Created: 2024-04-05
Related Issues:
Extension developers will be able to supply and define a set of icons to be used in the event that the user has expressed the preference for a page that has a dark theme.
- Improved icon visibility in the extension toolbar.
- Improved icon visibility on the management and shortcuts pages.
- Dark mode icon declarations made possible through the extension manifest.
setIcon()
will allow setting of dark and/or light mode specific icons.- Improved icon visibility on context menu (Chrome relies on default icons, only Firefox and Safari can specify menu icons).
- Improved icon visibility on side panel (Chrome relies on default icons, Firefox can specify icons).
The Chromium bug has a significant amount of developer interest.
manifest.json
"icon_variants": [
{
"any": "any.svg"
},
{
"16": "16.png",
"32": "32.png"
},
{
"16": "dark16.png",
"32": "dark32.png",
"color_schemes": ["dark"],
},
{
"16": "light16.png",
"32": "light32.png",
"color_schemes": ["dark", "light"]
}
],
"action": {
"icon_variants": [...]
}
icon_variants
requires an array with a set of icon groups objects. Each icon
group consists of a set of icon paths and icon group matching criteria.
The icon paths are set using the size as key and/or the keyword "any"
.
Optionally, color_schemes
matching is an array of string color schemes.
Setting icon_variants
dynamically:
const exampleProperties: {string: string | ImageData}[] = [
{
"any": "any.svg",
},
{
"16": "16.png",
"32": "32.png"
},
{
"16": darkImageData16,
"32": darkImageData32,
"color_schemes": ["dark"]
},
{
"16": lightImageData16,
"32": lightImageData32,
"color_schemes": ["light"]
}
];
// action.setIcon().
const createProperties = {variants: exampleProperties};
action.setIcon(createProperties);
// menus.*(), for supporting browsers.
const menusProperties = {icon_variants: exampleProperties};
menus.create(menusProperties);
menus.update(id, menusProperties);
A benefit of this new structure is that it's more resiliant to future changes, thus allowing for more keys such as density (e.g. 2dppx), purpose (e.g. monochrome), and etc.
Incumbent action.setIcon()
, for reference.
action.setIcon({
path,
tabId
imageData,
});
Existing manifest key. The behavior of the icons manifest key will remain unchanged.
{
"icons": {
"64": "icon_64.png"
},
"action": {
"default_icon": {
"64": "action_64.png"
}
}
}
Order of precedence. The new icon_variants
keys and subkeys will take
precedent, followed by the incumbent icons
key.
The dark
icon variant can be used by browsers to improve readability of the
icon. Often this will be when the OS or browser color scheme is dark (often
referred to as "dark mode") but also when the browser uses a darker shade theme
which has a background on which the dark icon variant would be more readable.
The light
icon variant is used otherwise.
N/A.
Summary
icon_variants
is offered as a replacement for icons
. icon_variants
aims
to be more flexible than pre-existing keys, allowing for unexpected declarations
without causing errors that prevents extension installation. Absent
color_schemes
declaration, any matching individual icon_variants
group will
effectively have a wild-card for color_schemes
. For example, ["*"]
is valid.
Misc
- If the top-level
icon_variants
key is provided, the top levelicons
key will be ignored. icon_variants
will not cause an error in the event that it is invalid. Instead, only the faulty icon group(s) will be ignored, with an optional warning. Warnings are preferred over errors because they're more adaptable to changes in the future.color-schemes
. Any icon group that does not contain acolor_schemes
key will apply to all available options, e.g. both "light" and "dark".- Group. If only one icon group is supplied, it will be used as the
default, i.e. any of its matching conditions will be ignored.
- In any icon group (aka in any icon variant), all types must be the same. For example, if one .png is supplied in a group, all other images in that group must also be .png. If more than one type is present in an icon group, the group can be ignored, marked as invalid and optionally show a warning during installation.
Matching
- If
icon_variants
contains an icon group with matching conditions, the icon (s) specified in the first matching icon group based on insertion order will be used. The other icon groups after that match will be ignored. - If there is more than one matching icon object, any without
color_schemes
will be applied to every possible color scheme. Therefore, a subsequent matching icon object with acolor_schemes
will not be used. - Incorrectly typed
color_schemes
values will be ignored, with an optional warning. For example,color_schemes: ["unknown"]
will be treated as an empty array. An empty array means the browser should mark the icon group as invalid and ignore it. - If only one icon object is defined with a specific color scheme, that icon object will be applied to all color schemes.
- Fuzzy matching Inexact size matches will return the icon closest in size, starting with smaller sizes if available, retreating to the nearest larger size.
Size
- The
"16"
is a size in{"16": "icon.png"}
and any number can be used as a size, per the browser’s icon requirements. The word"any"
can also be used in place of a number to represent an icon that can be shown at any size (usually vector images). The icon size used by the browser will be determined as follows: - Raster images: Sizes are in pixels. For high-density devices (2x, 3x,
etc.), the browser looks for double or triple the desired point size (e.g., 32
or 48 pixels for a 16 point request). If the exact pixel size is unavailable,
the next largest pixel size or
"any"
will be used. - Vector images: Sizes are in points, ensuring device independence. If the
exact point size is unavailable, an integer multiple (e.g. 32, 48, etc.) or
"any"
will be used. - If none of the specified icon groups have matching criteria, browsers should drop matching criteria in a specified order until it finds a group which results in a match. It will start by dropping any matching criteria which are unsupported/unknown. If still no match could be made, it will drop known matching criteria in a future agreed upon order.
action
- Any icons set programmatically using
action.setIcon()
would override manifest-defined icons. - For
”action”
icons, the browser first checks foricon_variants
in the action. If not specified, it falls back to default_icon, then to the top-levelicon_variants
or icons. action.setIcon({variants})
will not throw when giving it icon groups with properties it does not understand. Those icon groups will simply be ignored for making matches. If however, none of the icon groups are supported, an exception will be thrown allowing both feature detection and specifying fallbacks without requiring feature detection.
N/A.
N/A.
N/A.
- A developer could ask the user to specify what mode they're in and then
dynamically set the icon to a dark mode icon using
action.setIcon()
. That wouldn't change the management page icon. - A developer could change icons dynamically to dark mode icons if this is
true:
window.matchMedia('(prefers-color-scheme: dark)')
.
As stated in the workarounds section, the following is already an option to
consider: window.matchMedia('(prefers-color-scheme: dark)')
. However, that
wouldn't automatically set icons dynamically, as it would require subsequent
calls to action.setIcon()
. It also wouldn't update the icon on the management
pages.
N/A.
N/A.