Skip to content

Commit 61512ae

Browse files
solomonkinardRob--Woliverdunkcarlosjeurissenxeenon
authored
dark-mode: Add a proposal for dark mode extension icons (#585)
Co-authored-by: Rob Wu <[email protected]> Co-authored-by: Oliver Dunk <[email protected]> Co-authored-by: carlosjeurissen <[email protected]> Co-authored-by: Timothy Hatcher <[email protected]> Co-authored-by: Simeon Vincent <[email protected]>
1 parent 5869199 commit 61512ae

File tree

1 file changed

+268
-0
lines changed

1 file changed

+268
-0
lines changed
+268
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,268 @@
1+
# Dark Mode Extension Icons
2+
3+
**Summary**
4+
5+
Feature to enable developers to enhance extension icon visibility in dark mode.
6+
7+
**Document Metadata**
8+
9+
**Author:** solomonkinard
10+
11+
**Sponsoring Browser:** Chromium
12+
13+
**Contributors:** oliverdunk, xeenon, carlosjeurissen, hanguokai, dotproto
14+
15+
**Created:** 2024-04-05
16+
17+
**Related Issues:**
18+
* https://crbug.com/893175
19+
* https://github.com/w3c/webextensions/issues/229
20+
21+
## Motivation
22+
23+
### Objective
24+
25+
Extension developers will be able to supply and define a set of icons to be used
26+
in the event that the user has expressed the preference for a page that has a
27+
dark theme.
28+
29+
#### Use Cases
30+
31+
1. Improved icon visibility in the extension toolbar.
32+
1. Improved icon visibility on the management and shortcuts pages.
33+
1. Dark mode icon declarations made possible through the extension manifest.
34+
1. `setIcon()` will allow setting of dark and/or light mode specific icons.
35+
1. Improved icon visibility on context menu (Chrome relies on default
36+
icons, only Firefox and Safari can specify menu icons).
37+
1. Improved icon visibility on side panel (Chrome relies on default icons,
38+
Firefox can specify icons).
39+
40+
### Known Consumers
41+
42+
The Chromium bug has a significant amount of developer interest.
43+
44+
## Specification
45+
46+
### Examples
47+
48+
manifest.json
49+
```
50+
"icon_variants": [
51+
{
52+
"any": "any.svg",
53+
},
54+
{
55+
"16": "16.png",
56+
"32": "32.png",
57+
},
58+
{
59+
"16": "dark16.png",
60+
"32": "dark32.png",
61+
"color_scheme": "dark",
62+
},
63+
{
64+
"16": "light16.png",
65+
"32": "light32.png",
66+
"color_scheme": ["dark", "light"]
67+
}
68+
],
69+
"action": {
70+
"icon_variants": [...]
71+
}
72+
```
73+
`icon_variants` requires an array with a set of icon groups objects. Each icon
74+
group consists of a set of icon paths and icon group matching criteria.
75+
76+
The icon paths are set using the size as key and/or the keyword `"any"`.
77+
78+
Optionally the `color_scheme` matching criterium which can either be a string or
79+
array of color schemes.
80+
81+
Setting `icon_variants` dynamically:
82+
```
83+
const exampleProperties: {string: string | ImageData}[] = [
84+
{
85+
"any": "any.svg",
86+
},
87+
{
88+
"16": "16.png",
89+
"32": "32.png"
90+
},
91+
{
92+
"16": darkImageData16,
93+
"32": darkImageData32,
94+
"color_scheme": "dark"
95+
},
96+
{
97+
"16": lightImageData16,
98+
"32": lightImageData32,
99+
"color_scheme": "light"
100+
}
101+
];
102+
103+
// action.setIcon().
104+
const createProperties = {variants: exampleProperties};
105+
action.setIcon(createProperties);
106+
107+
// menus.*(), for supporting browsers.
108+
const menusProperties = {icon_variants: exampleProperties};
109+
menus.create(menusProperties);
110+
menus.update(id, menusProperties);
111+
```
112+
113+
A benefit of this new structure is that it's more resiliant to future changes,
114+
thus allowing for more keys such as density (e.g. 2dppx), purpose (e.g.
115+
monochrome), and etc.
116+
117+
## setIcon()
118+
Incumbent `action.setIcon()`, for reference.
119+
```
120+
action.setIcon({
121+
path,
122+
tabId
123+
imageData,
124+
});
125+
```
126+
127+
### Behavior
128+
129+
Existing manifest key. The behavior of the icons manifest key will remain
130+
unchanged.
131+
```
132+
{
133+
"icons": {
134+
"64": "icon_64.png"
135+
},
136+
"action": {
137+
"default_icon": {
138+
"64": "action_64.png"
139+
}
140+
}
141+
}
142+
```
143+
144+
Order of precedence. The new `icon_variants` keys and subkeys will take
145+
precedent, followed by the incumbent `icons` key.
146+
147+
The `dark` icon variant can be used by browsers to improve readability of the
148+
icon. Often this will be when the OS or browser color scheme is dark (often
149+
referred to as "dark mode") but also when the browser uses a darker shade theme
150+
which has a background on which the dark icon variant would be more readable.
151+
The `light` icon variant is used otherwise.
152+
153+
### New Permissions
154+
155+
N/A.
156+
157+
### Manifest File Changes [And API]
158+
159+
**Summary**
160+
161+
`icon_variants` is offered as a replacement for `icons`. `icon_variants` aims
162+
to be more flexible than pre-existing keys, allowing for unexpected declarations
163+
without causing errors that prevents extension installation. Absent
164+
`color_scheme` declaration, any matching individual `icon_variants` group will
165+
effectively have a wild-card `color_scheme`.
166+
167+
**Misc**
168+
1. If the top-level `icon_variants` key is provided, the top level `icons` key
169+
will be ignored.
170+
1. `icon_variants` will not cause an error in the event that it is invalid.
171+
Instead, only the faulty icon group(s) will be ignored, with an optional
172+
warning. Warnings are preferred over errors because they're more adaptable to
173+
changes in the future.
174+
1. `color-scheme`. Any icon group that does not contain a `color_scheme` key
175+
will apply to all available options, e.g. both "light" and "dark".
176+
1. **Group**. If only one icon group is supplied, it will be used as the
177+
default, i.e. any of its matching conditions will be ignored.
178+
* In any icon group (aka in any icon variant), all types must be the same.
179+
For example, if one .png is supplied in a group, all other images in that
180+
group must also be .png. If more than one type is present in an icon group,
181+
the group can be ignored, marked as invalid and optionally show a warning
182+
during installation.
183+
184+
**Matching**
185+
1. If `icon_variants` contains an icon group with matching conditions, the icon
186+
(s) specified in the first matching icon group based on insertion order will be
187+
used. The other icon groups after that match will be ignored.
188+
1. If there is more than one matching icon object, any without `color_scheme`
189+
will be applied to every possible color scheme. Therefore, a subsequent matching
190+
icon object with a `color_scheme` will not be used.
191+
1. Incorrectly typed `color_scheme` values will be ignored, with an optional
192+
warning. For example, `color_scheme: ["unknown"]` will be treated as an empty
193+
array. An empty array means the browser should mark the icon group as invalid
194+
and ignore it.
195+
1. If only one icon object is defined with a specific color scheme, that icon
196+
object will be applied to all color schemes.
197+
1. **Fuzzy matching** Inexact size matches will return the icon closest in size,
198+
starting with smaller sizes if available, retreating to the nearest larger size.
199+
200+
**Size**
201+
1. The `"16"` is a size in `{"16": "icon.png"}` and any number can be used as a
202+
size, per the browser’s icon requirements. The word `"any"` can also be used in
203+
place of a number to represent an icon that can be shown at any size (usually
204+
vector images). The icon size used by the browser will be determined as follows:
205+
1. **Raster images**: Sizes are in pixels. For high-density devices (2x, 3x,
206+
etc.), the browser looks for double or triple the desired point size (e.g., 32
207+
or 48 pixels for a 16 point request). If the exact pixel size is unavailable,
208+
the next largest pixel size or `"any"` will be used.
209+
1. **Vector images**: Sizes are in points, ensuring device independence. If the
210+
exact point size is unavailable, an integer multiple (e.g. 32, 48, etc.) or
211+
`"any"` will be used.
212+
1. If none of the specified icon groups have matching criteria, browsers should
213+
drop matching criteria in a specified order until it finds a group which results
214+
in a match. It will start by dropping any matching criteria which are
215+
unsupported/unknown. If still no match could be made, it will drop known
216+
matching criteria in a future agreed upon order.
217+
218+
**action**
219+
1. Any icons set programmatically using `action.setIcon()` would override
220+
manifest-defined icons.
221+
1. For `”action”` icons, the browser first checks for `icon_variants` in the
222+
action. If not specified, it falls back to default_icon, then to the top-level
223+
`icon_variants` or icons.
224+
1. `action.setIcon({variants})` will not throw when giving it icon groups with
225+
properties it does not understand. Those icon groups will simply be ignored for
226+
making matches. If however, none of the icon groups are supported, an exception
227+
will be thrown allowing both feature detection and specifying fallbacks without
228+
requiring feature detection.
229+
230+
## Security and Privacy
231+
232+
### Exposed Sensitive Data
233+
234+
N/A.
235+
236+
### Abuse Mitigations
237+
238+
N/A.
239+
240+
### Additional Security Considerations
241+
242+
N/A.
243+
244+
## Alternatives
245+
246+
### Existing Workarounds
247+
248+
1. A developer could ask the user to specify what mode they're in and then
249+
dynamically set the icon to a dark mode icon using `action.setIcon()`. That
250+
wouldn't change the management page icon.
251+
2. A developer could change icons dynamically to dark mode icons if this is
252+
true: `window.matchMedia('(prefers-color-scheme: dark)')`.
253+
254+
### Open Web API
255+
256+
As stated in the workarounds section, the following is already an option to
257+
consider: `window.matchMedia('(prefers-color-scheme: dark)')`. However, that
258+
wouldn't automatically set icons dynamically, as it would require subsequent
259+
calls to `action.setIcon()`. It also wouldn't update the icon on the management
260+
pages.
261+
262+
## Implementation Notes
263+
264+
N/A.
265+
266+
## Future Work
267+
268+
N/A.

0 commit comments

Comments
 (0)