1. Introduction
This specification introduces three new features related to controlling how/when colors are auto-adjusted by the user agent:
-
Color schemes and the color-scheme property, which controls whether or not browser-provided parts of the page’s UI respect the user’s chosen color scheme.
-
Forced colors mode and the forced-color-adjust property, which controls whether or not forced colors mode is allowed to apply to a given element.
-
The print-color-adjust property, which controls whether the browser is allowed to automatically adjust colors to the user’s assumed performance preferences, such as suppressing background colors when printing to save ink.
Together with the prefers-color-scheme, prefers-contrast, and forced-colors media queries [MEDIAQUERIES-5], this module allows color scheme negotiation between the author and the user.
1.1. Value Definitions
This specification follows the CSS property definition conventions from [CSS2] using the value definition syntax from [CSS-VALUES-3]. Value types not defined in this specification are defined in CSS Values & Units [CSS-VALUES-3]. Combination with other CSS modules may expand the definitions of these value types.
In addition to the property-specific values listed in their definitions, all properties defined in this specification also accept the CSS-wide keywords as their property value. For readability they have not been repeated explicitly.
2. Preferred Color Schemes
Operating systems and user agents often give users the ability to choose their preferred color scheme for user interface elements. This color scheme is typically reflected in the user agent’s rendering of its navigation interface as well as in-page interface elements such as form controls and scrollbars.
A UA can also allow the user to indicate a preference for the color scheme of the pages they view, requesting that the author adapt the page to those color preferences. (It is not required to express such a preference; users can have preferences for operating system interface colors that they do not want imposed on pages.)
The most common color scheme preferences are:
-
A light color scheme ("day mode") consists of light background colors and dark foreground/text colors.
-
A dark color scheme ("night mode") consists of the opposite, with dark background colors and light foreground/text colors.
Note: Light and dark color schemes are not specific color palettes, but a range of possible palettes. For example, a stark black-on-white scheme and a sepia dark-on-tan scheme would both be considered light color schemes. To guarantee specific colors, authors must specify those colors themselves. Note also that, consequently, pairing default or <system-color> colors with author-specified colors cannot guarantee any particular contrast level; to ensure legibility, generally either both foreground and background should be paired system colors or both be manually specified colors. [WCAG22]
The user’s preferred color scheme is then combined with the page’s supported color schemes to produce a page color scheme. The page color scheme also records whether it’s default or not. The page color scheme is queryable with the prefers-color-scheme media query. [MEDIAQUERIES-5]
Individual elements have an element color scheme, which by default matches the page color scheme, but can be overriden using the color-scheme property. The element color scheme affects things such as the value of system colors on the element, the value of the light-dark() function, and how user interface elements (like scrollbars) render. (See § 2.4 Effects of the Used Color Scheme.)
User agents may support additional color schemes, however CSS does not support negotiation of additional color schemes: user agents should pursue standardization of these schemes, so that prefers-color-scheme and color-scheme can reflect the additional values.
Note: Because many pages were authored before color scheme support existed, and thus pages were authored with the assumption of the default (light) color scheme, user agents cannot automatically adapt the colors used in elements under their control, as it might cause unreadable color contrast with the surrounding page. Pages have to opt into color scheme support by setting the page color scheme, or manually setting the color-scheme property on individual elements.
2.1. Opting Into a Preferred Color Scheme
The page color scheme represents the color scheme that will be used for the page overall (queryable with the prefers-color-scheme media feature) and for all elements that don’t specifically override the page color scheme with the color-scheme property. See § 2.4 Effects of the Used Color Scheme for a full description of what the color scheme effects.
Note: In HTML, the color-scheme <meta>
sets the page color scheme.
Authors should generally set the page color scheme, rather than using the color-scheme property, so that the prefers-color-scheme media feature is consistent with the elements on the page.
The page color scheme is determined by finding the used color scheme, given the preferred color scheme and the page’s supported color schemes (a color scheme support).
In embedded documents
(such as an iframe or an SVG img),
the embedding element’s element color scheme
is used as the embedded document’s preferred color scheme
(treated as a normal color scheme preference),
rather than the user’s preference.
This allows embedded documents to match the negotiated color scheme
for the page or an element,
similar to other elements in the parent document.
< meta name = color-scheme contents = "light dark" >
(Or, in languages that don’t have a way to set the page color scheme directly, a :root { color-scheme: light dark;} rule.)
If a page limits itself to using only the <system-color>s, the color-scheme declaration will support the user’s preferred color scheme even without the author needing to use @media at all.
color-scheme or color-scheme
can still indicate which color schemes the page can support,
causing the UI to match.
If the page’s color scheme is primarily light, the following will indicate that explicitly:
< meta name = color-scheme contents = "light" >
While if the page is primarily dark, indicating that explicitly will make the page look more coherent as well:
< meta name = color-scheme contents = "dark" >
However, it is better to support both color schemes, of course.
2.2. Overriding the Page Color Scheme: the color-scheme property
| Name: | color-scheme |
|---|---|
| Value: | normal | [ light | dark | <custom-ident> ]+ && only? |
| Initial: | normal |
| Applies to: | all elements and text |
| Inherited: | yes |
| Percentages: | n/a |
| Computed value: | the keyword normal, or a color scheme support |
| Canonical order: | per grammar |
| Animation type: | discrete |
While the page color scheme should generally be used to control what color scheme a page uses, occasionally there is need to override that color scheme on a particular subtree. The color-scheme property allows this, manually setting the element color scheme for an element and its descendants. Values are defined as follows:
- normal
-
The element color scheme is the same as the page color scheme. (This includes noting whether the color scheme was defaulted.)
- light
- dark
-
Indicates that the element supports a light and/or dark color scheme, as appropriate. The element’s color scheme support will include the keywords, in the order they’re specified.
- only
-
Forbids the user agent from overriding the color scheme for the element. The element’s color scheme support will have a flag indicating sole support.
- <custom-ident>
-
<custom-ident> values are meaningless, and exist only for future compatibility, so that future added color schemes do not invalidate the color-scheme declaration in legacy user agents. User agents must not interpret any <custom-ident> values as having a meaning; any additional recognized color schemes must be explicitly added to this property’s grammar.
Note: To avoid confusion, authoring tutorials and references should omit <custom-ident> from their materials.
The normal, light, dark, and only keywords are not valid <custom-ident>s in this property.
If an element has any value other than color-scheme: normal, its element color scheme is determined by finding the used color scheme, given the user’s preferred color scheme and the element’s color scheme support specified by this property.
For example, a style guide might give several UI examples that are using light or dark colors, showing off the light or dark theme specifically. This can be indicated as:
< meta name = color-scheme content = "light dark" > < style > . light-theme-example { color-scheme : light ; } . dark-theme-example { color-scheme : dark ; } </ style >
Only the subsections rooted at .light-theme-example or .dark-theme-example will be opted into the light or dark themes specifically; the rest of the page will respect the user’s preference.
Note: Repeating a keyword, such as color-scheme: light light, is valid but has no additional effect beyond what the first instance of the keyword provides.
2.3. Resolving Color Schemes
While it’s important for a page to respect the user’s preferred color scheme, it’s also important to only use a color scheme the page author expects, or else it is very easy to render a page unreadable by causing the foreground and background elements to accidentally have minimal (or zero!) contrast.
For example, an author expecting the default light color scheme might set the page background to a light cream while leaving the text color unset, expecting it to use the default black text color. If the page unexpectedly opted into a user’s preferred dark color scheme, however, and adjusted the default text color to white, that would make the text virtually unreadable.
To balance these competing concerns, a user’s color scheme preference is compared against a page’s color scheme support to produce a used color scheme.
A color scheme preference is either no preference, a color scheme preference (light or dark), or an overriding color scheme preference.
A color scheme support is null, or an ordered list of one or more supported color schemes, along with a flag indicating whether or not it solely supports the indicated color schemes.
-
If support is null, or none of the color schemes in support are supported by the UA, return the UA default color scheme, and annotate that this color scheme was defaulted.
-
If preference is no preference, return the first supported color scheme in support.
-
If preference’s color scheme is in support and supported by the UA, return that color scheme.
-
If support is flagged as sole support, return the first supported color scheme in support.
-
If preference is an overriding preference, return preference’s color scheme. If this color scheme is used as an element color scheme, also override the color scheme on the element to this color scheme.
-
Otherwise, return the first supported color scheme in support.
Note: The basic logic here is that, if the page hasn’t opted into color schemes at all (null supports), we go with the safe UA default that it was probably implicitly designed for. If there is a usable supports, and it matches preference, we use the preference. Otherwise preference and supports disagree, and we go back and forth down the preference hierarchy to see who wins: sole support in support wins, then overriding preference in preference wins (and we adjust the element’s colors to make sure this actually works), then support finally wins.
Note: User agents are not required to support any particular color scheme, so only using a single keyword, such as color-scheme: dark, to indicate a required color scheme is still not guaranteed to have any effect on the rendering of the element.
Note: User agents might not actually support preference levels in a color scheme preferences. At the time of writing, UAs generally only support an ordinary light or dark preference, which considerably simplifies the above logic.
2.4. Effects of the Used Color Scheme
For all elements, the user agent must match the following to the element color scheme:
-
the default colors of scrollbars and other interaction UI
-
the default colors of form controls and other "specially-rendered" elements
-
the default colors of other browser-provided UI, such as "spellcheck" underlines
-
the value of system colors
-
the value of the light-dark() function
On the root element, the element color scheme additionally must affect the surface color of the canvas, and the viewport’s scrollbars.
In order to preserve expected color contrasts,
in the case of embedded documents typically rendered over a transparent canvas
(such as provided via an HTML iframe element),
if the element color scheme of the element
and the element color scheme of the embedded document’s root element
do not match,
then the UA must use an opaque canvas of the Canvas color
appropriate to the embedded document’s root element’s element color scheme
instead of a transparent canvas.
This rule does not apply to documents embedded
via elements intended for graphics
(such as img elements embedding an SVG document);
their canvases remain the default transparent regardless.
Note: Aside from the small list of adjustments given above, user agents generally do not further adjust a page to match the user’s preferred color scheme, because the chance of accidentally ruining a page is too high. However, when particular color choices are required by the user (for accessibility reasons, for example), more invasive changes might be applied; see § 3 Forced Color Palettes.
2.5. Overriding the Color Scheme
If the user has indicated an overriding preference for a particular color scheme that the author does not explicitly support, and the author has not disallowed this (by using the only keyword), the user agent must override the color scheme: in addition to the effects described in § 2.4 Effects of the Used Color Scheme, it must also auto-adjust other colors into this chosen color scheme, such as by inverting their brightness, while preserving any color contrast necessary for readability of the page. In this case, UA may also auto-adjust colors within replaced elements, background images, and other external resources as appropriate.
Note: The specifics of such auto-adjustments are UA-defined, and can differ from UA to UA. But it is not intended to force all colors into a fixed palette, as forced colors mode does, only to force all colors on the page to conform to either a dark or light color scheme.
For pages that already support dark color schemes,
and have indicated so using the color-scheme property
or color-scheme meta name,
this has no effect other than reporting a dark value
for the prefers-color-scheme media query
and selecting a dark used color scheme.
But for pages that do not explicitly support a dark color scheme, and have not explicitly forbidden this auto-adjustment by specifying color-scheme: only light, this mode triggers auto-adjustment of the page’s colors to force the page to conform to the desired dark color scheme.
3. Forced Color Palettes
Forced colors mode is an accessibility feature intended to increase the readability of text through color contrast. Individuals with limited vision often find it more comfortable to read content when there is a particular type of contrast between foreground and background colors.
Operating systems can provide built-in color themes, such as Windows’ high contrast black-on-white and high-contrast white-on-black themes. Users can also customize their own themes, for example to provide low contrast or hue contrast.
In forced colors mode, the user agent enforces the user’s preferred color palette on the page, overriding the author’s chosen colors for specific properties, see § 3.1 Properties Affected by Forced Colors Mode. It may also enforce a “backplate” underneath text (similar to the way backgrounds are painted on the ::selection pseudo-element) to ensure adequate contrast for readability.
To enable pages to adapt to forced colors mode user agents will match the forced-colors media query and must provide the required color palette through the CSS system colors (see [CSS-COLOR-4]). Additionally, if the UA determines, based on Lab lightness, that the Canvas color is clearly either dark (L < 33%) or light (L > 67%), then it must match the appropriate value of the prefers-color-scheme media query and express a corresponding user preference for color-scheme. This will allow pages that support light/dark color schemes to automatically adjust to more closely match the forced color scheme. Behavior between the above dark vs. light thresholds is UA-defined, and may result in assuming either light or dark as the user’s preferred color scheme.
If get emulated forced colors theme data
is not "none",
the user agent should bypass the above operating system color themes,
and instead act as if the user has enabled forced colors mode
with the forced colors mode emulation color palette defined for
the resulting value of emulated forced colors theme data.
3.1. Properties Affected by Forced Colors Mode
When forced colors mode is active and forced-color-adjust is auto (see below) on an element, the <color> components of all properties on the element are force-adjusted to the user’s preferred color palette.
For each <color> component of a property, if its computed value is a color other than a system color, its used value is instead forced to a system color as follows:
-
For background-color in particular, it is forced to the color opposite the color property’s system color value in the system color pairings, using CanvasText as the opposite of Canvas. However, its alpha channel is taken from the original background-color value so that transparent backgrounds remain transparent.
-
In all other cases, the UA determines the appropriate forced system color—which should match the color that would result from an empty author style sheet whenever all of the element’s affected properties are likewise UA-determined.
UAs need to be careful about inheritance when forcing colors. For example, suppose the UA’s button color and background-color are the opposite of its canvas color and background-color. Given markup such as< button > Push< em > this</ em > button</ button > Normally,
emwill inherit frombutton, ensuring its readability. However in forced colors mode, the color of bothbuttonandemwill need to be forced. It’s easy to see thatbutton’s color should be forced to the button color, butemalso needs to be forced to the button color; if it were forced to the canvas color like it is everywhere else in the document, its text will be unreadable.
Additionally:
-
box-shadow and text-shadow compute to none
-
background-image computes to none unless the original value contains a url() function
-
color-scheme computes to light dark
-
scrollbar-color computes to auto
-
accent-color computes to auto
-
If font-variant-emoji computes to normal or unicode, UAs should force any emoji on the page to its monochrome variant, if available, by forcing the computed value of font-variant-emoji to text.
UAs may further tweak these forced colors mode heuristics to provide better user experience.
.example{ color : color-mix ( in srgb, CanvasText, Canvas); }
The computed value for color will be a 50-50 blend of the CanvasText and Canvas system colors.
That value will inherit to descendants and be observable via APIs such as computedStyleMap().
The used value for color will be a system color chosen by the UA, for example CanvasText.
3.2. Opting Out of a Forced Color Palette: the forced-color-adjust property
| Name: | forced-color-adjust |
|---|---|
| Value: | auto | none | preserve-parent-color |
| Initial: | auto |
| Applies to: | all elements and text |
| Inherited: | yes |
| Percentages: | n/a |
| Computed value: | as specified |
| Canonical order: | per grammar |
| Animation type: | not animatable |
The forced-color-adjust property allows authors to opt particular elements out of forced colors mode, restoring full control over the colors to CSS. Values have the following meanings:
- auto
-
The element’s colors are automatically adjusted by the UA in forced colors mode.
- none
-
The element’s colors are not automatically adjusted by the UA in forced colors mode.
Authors should only use this value when they are themselves adjusting the colors to support the user’s color and contrast needs and need to make changes to the UA’s default adjustments to provide a more appropriate user experience for those elements.
- preserve-parent-color
-
In forced colors mode, if the color property inherits from its parent (i.e. there is no cascaded value or the cascaded value is currentColor, inherit, or another keyword that inherits from the parent), then it computes to the used color of its parent’s color value.
In all other respects, behaves the same as none.
Note: This value is intended solely to get a reasonable behavior from embedded SVG elements that expect to receive the outer document’s text color (and stay consistent with adjustments from forced colors mode), while otherwise defaulting SVGs to preserving their exact colors, as forced colors mode can’t generally be usefully applied to illustrations.
In order to not break SVG content, UAs are expected to add the following rules to their UA style sheet:
@namespace "http://www.w3.org/2000/svg" ; svg|svg{ forced-color-adjust : preserve-parent-color; } svg|foreignObject{ forced-color-adjust : auto; }
UAs must propagate the forced-color-adjust value set on the root element
to the document viewport
(where it can affect e.g. the canvas background).
Note that forced-color-adjust is not propagated from HTML body.
4. Performance-based Color Adjustments
On most monitors, the color choices that authors make have no significant difference in terms of how the device performs; displaying a document with a white background or a black background is approximately equally easy.
However, some devices have limitations and other qualities that make this assumption untrue. For example, printers tend to print on white paper; a document with a white background thus has to spend no ink on drawing that background, while a document with a black background will have to expend a large amount of ink filling in the background color. This tends to look fairly bad, and sometimes has deleterious physical effects on the paper, not to mention the vastly increased printing cost from expending the extra ink. Even fairly small differences, such as coloring text black versus dark gray, can be quite different when printing, as it switches from using a single black ink to a mixture of cyan, magenta, and yellow ink, resulting in higher ink usage and lower resolution.
As a result, in some circumstances user agents will alter the styles an author specifies in some particular context, adjusting them to be more appropriate for the output device and to accommodate what they assume the user would prefer. However, in some cases the document may be using colors in important, well-thought-out ways that the user would appreciate, and so the document would like some way to hint to the user agent that it might want to respect the page’s color choices. This section defines properties for controlling these automatic adjustments.
4.1. Ink Economy: the print-color-adjust property
| Name: | print-color-adjust |
|---|---|
| Value: | economy | exact |
| Initial: | economy |
| Applies to: | all elements |
| Inherited: | yes |
| Percentages: | N/A |
| Computed value: | specified keyword |
| Canonical order: | per grammar |
| Animation type: | discrete |
The print-color-adjust property provides a hint to the user-agent about how it should treat color and style choices that might be expensive or generally unwise on a printer or similar device, such as using light text on a dark background. If user agents allow users to control this aspect of the document’s display, the user preference must be respected more strongly than the hint provided by print-color-adjust. It has the following values:
- economy
-
The user agent should make adjustments to the page’s styling
as it deems necessary and prudent for the output device.
For example, if the document is being printed, a user agent might ignore any backgrounds and adjust text color to be sufficiently dark, to minimize ink usage.
- exact
-
This value indicates that the page is using color and styling on the specified element
in a way which is important and significant,
and which should not be tweaked or changed except at the user’s request.
For example, a mapping website offering printed directions might "zebra-stripe" the steps in the directions, alternating between white and light gray backgrounds. Losing this zebra-striping and having a pure-white background would make the directions harder to read with a quick glance when distracted in a car.
UAs must propagate the print-color-adjust value set on the root element
to the document viewport
(where it can affect e.g. the canvas background).
Note that print-color-adjust is not propagated from HTML body.
4.2. The color-adjust Shorthand
| Name: | color-adjust |
|---|---|
| Value: | <'print-color-adjust'> |
| Initial: | see individual properties |
| Applies to: | see individual properties |
| Inherited: | see individual properties |
| Percentages: | see individual properties |
| Computed value: | see individual properties |
| Animation type: | see individual properties |
| Canonical order: | per grammar |
The color-adjust shorthand allows an author to set all of the performance-motivated color adjustment properties in one declaration. (Currently, there is only one such property—print-color-adjust—but more might be added in the future.)
The color-adjust shorthand is currently deprecated. Authors should use the more specific print-color-adjust property, to avoid accidentally resetting performance-based color adjustments in other contexts than the one intended.
5. Emulation
For the purposes of user agent automation and application testing, this document defines the below emulations.5.1. Emulate Forced Colors Mode
Each top-level traversable has an associated
emulated forced colors theme data, which is data representing
ForcedColorsModeAutomationTheme, initially "none".
enum {ForcedColorsModeAutomationTheme ,"none" ,"light" };"dark"
To set emulated forced colors theme data, given navigable navigable and an emulatedThemeData:
-
Assert emulatedThemeData is
ForcedColorsModeAutomationTheme. -
Let traversable be navigable’s top-level traversable.
-
If traversable is not null:
-
Set traversable’s associated emulated forced colors theme data to emulatedThemeData.
-
UAs must consider this a change that requires style recalculation.
-
To get emulated forced colors theme data, given ForcedColorsModeAutomationTheme
theme:
-
Let navigable be theme’s relevant global object’s associated Document’s node navigable.
-
If navigable is null, return null.
-
Let traversable be navigable’s top-level traversable.
-
If traversable is null, return null.
-
Return traversable’s associated emulated forced colors theme data.
5.2. Forced Colors Mode Color Palettes
For the purposes of user agent automation and application testing, this document defines the below forced colors mode emulation color palettes.| <system-color> keyword | Value |
|---|---|
| AccentColor | #FFFFFF |
| AccentColorText | #000000 |
| ActiveText | #00009F |
| ButtonBorder | #000000 |
| ButtonFace | #FFFFFF |
| ButtonText | #000000 |
| Canvas | #FFFFFF |
| CanvasText | #000000 |
| Field | #FFFFFF |
| FieldText | #000000 |
| GrayText | #600000 |
| Highlight | #37006E |
| HighlightText | #FFFFFF |
| LinkText | #00009F |
| Mark | N/A - this system color keyword should not be adjusted. |
| MarkText | N/A - this system color keyword should not be adjusted. |
| SelectedItem | #37006E |
| SelectedItemText | #FFFFFF |
| VisitedText | #00009F |
| <system-color> keyword | Value | |
|---|---|---|
| AccentColor | #000000 | |
| AccentColorText | #FFFFFF | |
| ActiveText | #FFFF00 | |
| ButtonBorder | #000000 | |
| ButtonFace | #000000 | |
| ButtonText | #FFFFFF | |
| Canvas | #000000 | |
| CanvasText | #FFFFFF | |
| Field | #000000 | |
| FieldText | #FFFFFF | |
| GrayText | #3FF23F | |
| Highlight | #1AEBFF | |
| HighlightText | #000000 | |
| LinkText | #FFFF00 | |
| Mark | N/A - this system color keyword should not be adjusted. | |
| MarkText | N/A - this system color keyword should not be adjusted. | |
| SelectedItem | #1AEBFF | |
| SelectedItemText | #000000 | |
| VisitedText | #FFFF00 |
6. Privacy Considerations
Applying user color preferences via color schemes or forced colors mode
exposes the user’s color preferences to the page
via getComputedStyle(),
which can increase fingerprinting surface.
-
preserving system colors as keywords until actual-value time would break a significant amount of deployed script, as the initial value of color is a system color already (but a huge amount of script implicitly expects to see an RGB color from color)
-
lying about system colors from the scripting APIs (pretending they’re always some static values) can result in any colors calculated from page colors in script being unreadable when used with the actual system colors.
See Issue 5710 for discussion on this topic.
Embedded documents (even cross-origin ones) recieve their embedding element’s element color scheme as their preferred color scheme, which is technically a bit of cross-site communication. This was not considered a significant problem by browser security reviewers, and the user benefit of having pages and, particularly, SVG images automatically adapt to the parent page’s color scheme was considered valuable enought to warrant it.
7. Security Considerations
It may be possible for an embedded document
to use timing attacks to determine whether its own color-scheme
matches that of its embedding iframe or not.
8. Acknowledgements
This specification would not be possible without the development efforts of various color adjustment features at Apple, Google, and Microsoft as well as discussions about print adjustments on www-style. In particular, the CSS Working Group would like to thank: François Remy, イアンフェッティ
List additional MSFT / Apple / Google people here.
9. Changes
Changes since the 10 February 2022 Candidate Recommendation Snapshot:
- Removed special handling of color() fallback system colors, since the feature was removed from [CSS-COLOR-4]. (Issue 7007)
- Added emulation support for improved testing of forced colors mode. (Issue 11824)
- Updated the properties that apply in forced colors mode to more generically apply to the <color> components of all properties, with specific known properties moved to a note. (Issue 11857)
- Added font emoji fallback logic for forced colors mode. (Issue 8064)