Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-color-adjust-1] Is forced color computed or used value? #4915

Closed
fantasai opened this issue Apr 2, 2020 · 10 comments
Closed

[css-color-adjust-1] Is forced color computed or used value? #4915

fantasai opened this issue Apr 2, 2020 · 10 comments
Labels
Closed Accepted by CSSWG Resolution Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. css-color-adjust-1 Current Work

Comments

@fantasai
Copy link
Collaborator

fantasai commented Apr 2, 2020

Follow-up to #4175

We are now computing background-color based on the computed 'color' value. (Specifically, we're keying off the computed color to find a color, and forcing all but the author’s specified alpha channel to match that color.)

Is this computation at computed-value time or used-value time for background-color?

@fantasai fantasai added the css-color-adjust-1 Current Work label Apr 2, 2020
@tabatkins
Copy link
Member

It has to be at used-value time, due to the system color keywords not resolving until then, right?

@andruud
Copy link
Member

andruud commented May 4, 2020

If the adjusted background-color exists computed-value time, it means there are two right answers (/two wrong answers?) for what the computed-value is for background-color. The author alpha doesn't exist separately from background-color, hence the computed value of background-color must be computed to know the author alpha. We shouldn't then suddenly redefine the computed value after it has already been determined the first time. So used-value time seems like a better choice.

@AmeliaBR
Copy link
Contributor

AmeliaBR commented May 4, 2020

It would be a little weird if all the other forced-color effects are available at computed time, but background-color is naively reported without adjustments.

It has to be at used-value time, due to the system color keywords not resolving until then

Yes, but the other colors at least compute correctly to a system color.

Ideally, we would define the computed value of background-color using one of the Colors Level 5 mixing functions: this system color, but adjusted to use that alpha.

the computed value of background-color must be computed to know the author alpha. We shouldn't then suddenly redefine the computed value after it has already been determined

This is also true, and trickier to work around.

Logically, we want to treat background-color as if it is a shorthand for background-color-color and background-color-alpha. The author computed background-color sets both of these hypothetical longhands, and then the forced user agent style overrides the first but not the second. Using that shorthand/longhand model, the overriding would happen at computed value time.

A comparison would be font: caption; font-size: 16px. There is no way to serialize a font shorthand representing the combined result without first substituting the expanded value of the system font keyword.

But of course, the difference is that system fonts are substituted at computed time, and they do have longhand properties that can inherit only part of that value. So, I'm not sure we can reuse that model without a serious re-think to all this.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Is forced background-color computed or used value?, and agreed to the following:

  • RESOLVED: The color computed values are defined as used values using the color mix function
The full IRC log of that discussion <dael> Topic: Is forced background-color computed or used value?
<dael> github: https://github.com//issues/4915
<dael> Rossen_: This is in the context of forced-colors-adjust.
<dael> Rossen_: Short summary is in the previous impl of what used to be ms-high-contrast and is now forced-colors we were reverting colors incl background and override with system color
<dael> Rossen_: At the time at MS we didn't consider taking in the alpha channel of the color value.
<dael> Rossen_: That meant simply all overrides were stable during computed and alpha was always opauqe
<dael> Rossen_: When working on focred-colors one addition to the feature is addition of considering alpha channel of the color. For background-color it means we now have to compute the final color value during used time
<dael> Rossen_: That's how issue came about. Is it supposed to be computed or used.
<dael> Rossen_: Is amelia_br or fantasai on?
<dael> TabAtkins: We have me and I commented
<dael> TabAtkins: Seems clear this needs to be used value time transformation
<dael> TabAtkins: because we can't do anything with a system color until we resolve it which is at used value time b/c need to know color scheme
<dael> TabAtkins: This is to make it reasonably work. Amelia's comment brings up the very good point that color mix function would be useful for this.
<dael> TabAtkins: If you want to define a computed value that's this system color but with the other alpha you can do it simply with color mix function.
<dael> TabAtkins: We could and should define computed value of color becomes a color mix function with alpha from previous color and mix with system color
<dael> Rossen_: What do we serialize in OM? used value?
<dael> TabAtkins: All current properties do used
<dael> Rossen_: Okay, that continues to work
<dael> TabAtkins: Not 100% clear/remember what happens in image properties. But plain colors do used value.
<dael> Rossen_: The ones covered by color-adjust are covered.
<dael> TabAtkins: Yeah
<dael> emilio: Not quite used value because :visited and so on
<dael> Rossen_: sure
<dael> TabAtkins: Ignoring :visited hacks they are always used values
<dael> Rossen_: Sounds like a good path forward for this behavior
<dael> Rossen_: Any other considerations or proposals to consider?
<dael> TabAtkins: If we go with this is means impl should prioritize color mix.
<dael> TabAtkins: Also solves that you can't transition system colors since you can use color mix for that.
<dael> Rossen_: Sounds good
<dael> Rossen_: Looking for your summary
<TabAtkins> color-mix(appropriate-system-color, specified-color a(100%))
<dael> Rossen_: Prop: The color computed values are defined as used values using the color mix function
<dael> Rossen_: Objections?
<dael> RESOLVED: The color computed values are defined as used values using the color mix function

@svgeesus
Copy link
Contributor

@tabatkins wrote:

color-mix(appropriate-system-color, specified-color a(100%))

As specified, that will do the [color interpolation(https://drafts.csswg.org/css-color-5/#interpolation) in the LCH colorspace, which is the default. That might not be what is wanted however. I can think of two other options:

color-mix(appropriate-system-color, specified-color a(100%) srgb)

That will mix in the (gamma corrected, i.e. non-linear-light) sRGB colorspace, which is what the current implementations do when mixing colors. It gives the wrong (too dark) result but is compatible with lots of software which also does it the wrong way :) It is also constrained to the sRGB gamut, which is temporarily fine but won't be over time as some system colors may be specified in, for example, display-p3.

color-mix(appropriate-system-color, specified-color a(100%) xyz)

That will get you linear-light mixing, ie the correct result for the physical mixture of two lights, and avoids gamut mapping. It gives the same result as mixing in linear-light sRGB, except without the gamut limitation.

@tabatkins
Copy link
Member

This might be moot anyway (if it's specified as happening at used-value time, from other issues), but if we do keep with "forced-colors mode causes the computed value to be a color-mix() function", it's only mixing alpha (and "mixing" only in a degenerate sense; it's just taking the source color's alpha entirely); the rest of the channels are taken solely from the system color. So the colorspace we mix in is moot.

@fantasai
Copy link
Collaborator Author

Given the resolutions to adopt @FremyCompany's proposals in #4915, I would like to re-open this issue (see #4178 (comment)).

The concept we adopted in #4178 was to treat non-system colors as “out of gamut”, effectively. Mapping out-of-gamut colors is a used-value time operation, not a computed-value time operation. There's an added benefit to making this a used-value time operation: it also makes the question of transitions and interpolation (see #5419) go away. So my proposal is that we go with making this a used-value time operation rather than a computed-value time operation.

Next question is, should we do the same for the other affected properties (which are not color properties) and force their used values to the initial value, instead of their computed values?

@fantasai fantasai added this to Awaiting CSSWG in Tab and fantasai Await Oct 13, 2020
@fantasai fantasai changed the title [css-color-adjust-1] Is forced background-color computed or used value? [css-color-adjust-1] Is forced color computed or used value? Oct 13, 2020
@fantasai
Copy link
Collaborator Author

Another (important, imho) benefit of forcing colors at used-value time is that they will inherit as the author-specified value, so if a subtree opts out of forced colors, it will use the author-specified colors, not a mix of author-specified and forced colors.

@astearns astearns added this to the TPAC-2020-08-22 milestone Oct 16, 2020
@alisonmaher
Copy link
Collaborator

I wanted to +1 @fantasai's point in the above comment.

In particular, forcing at used-value time will likely be helpful for the following case:

<style>
  body {
    color: red;
  }
</style>
<body>
  <svg>
    <rect width="100" height="100" fill="white"/>
    <text x="0" y="15" fill="currentColor">Test</text>
  </svg>
</body>

We set forced-color-adjust: none on SVG elements in Forced Colors Mode. Thus, in the above example, when Forced Colors Mode is enabled to the white-on-black theme, the SVG rectangle will remain filled with white, but since the text fill is set to currentColor, it will become unreadable since it will inherit a white forced color from its parent.

If we were to force colors at used-value time, instead, the text fill would pick up red and would remain readable in Forced Colors Mode.

So although changing this to used-value time may complicate the implementation a bit, I do think that there is value in changing this to a used-value time operation.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-color-adjust-1] Is forced color computed or used value?, and agreed to the following:

  • RESOLVED: Forced colors happens at used value time. Add a note to the spec about implementation
The full IRC log of that discussion <emilio> topic: [css-color-adjust-1] Is forced color computed or used value?
<fantasai> github: https://github.com//issues/4915#issuecomment-701674628
<emilio> fantasai: I reopened in light on the resolutions we took to adopt fremy's proposal in the previous issue
<emilio> ... we decided than rather than a cascade-time revert and consider them out-of-gamut for non-system colors
<emilio> ... which is a different technique
<emilio> ... but out-of-gamut mapping is a used-time op, not computed-time
<emilio> ... by doing it at computed-value time we got weird behavior wrt ??
<emilio> s/??/inheritance
<emilio> fantasai: when you do it at computed value then it'll change it to system color and then inherit
<emilio> ... if you have a forced-color-adjust: none section down the page
<emilio> ... expecting a particular inherited color
<emilio> ... but instead you get a random system color which might be unreadable
<emilio> ... if we do this mapping at used value time
<florian> q+
<emilio> ... then it inherits the color properly
<fremy> q+
<emilio> ... but the ancestor with forced colors will get the system color at used value time
<emilio> q+
<emilio> TabAtkins: I think I agree on this, makes much more sense
<TabAtkins> s/think I/strongly/
<emilio> Rossen_: it also avoids the dependency with color-mix()
<florian> q-
<emilio> fantasai: yeah prevents all the interpolation / transitions issues
<Rossen_> ack fremy
<emilio> fremy: I think it does make a lot of sense but I want to make sure something is recorded
<emilio> ... if you have a disabled button, the default style will have some color
<emilio> ... let's say `text` -> `disabledtext`
<emilio> ... so it can be made at used value time
<emilio> ... but for children you need to walk the parent chain to know which color to reset
<emilio> ... basically what you map to depends on the UA stylesheets
<emilio> ... so you kinda need to remember this in a way
<emilio> florian: [restates the issue]
<emilio> TabAtkins: it is indeed a separate concern
<emilio> fremy: I wanted to make sure it's mentioned because it's an important impl detail
<emilio> fantasai: Yeah we should note that in the spec
<emilio> florian: if we were doing it at computed value time you wouldn't have to do it so it's the same issue, not separate
<Rossen_> q
<Rossen_> ack emilio
<fantasai> emilio: Wanted to mention related point
<fantasai> emilio: this is a problem, even if you don't account for children
<fantasai> emilio: if you specify color on the button
<fantasai> emilio: in order to know what to revert to, need to do the cascade again
<fantasai> emilio: to find the original value to revert to
<fantasai> emilio: that would be my main concern
<fantasai> emilio: I think it could be addressed with something like an internal CSS property
<fantasai> emilio: but different from what browsers currently do
<fantasai> fremy: similar to :visited
<fantasai> emilio: similar, but different
<fantasai> fremy: this is what Edge did, we tracked a separate value
<fantasai> s/value/value for :visited
<fantasai> Rossen_: We had a cascaded value alongside, for anything that was overridden, so that we didn't have to go and recascade
<fantasai> Rossen_: we would have it at hand, ready to use as needed.
<fantasai> Rossen_: Added a little bit of memory, but relatively insignificant
<fantasai> Rossen_: so from impl pov, this is very doable, not much additional context needed
<fantasai> Rossen_: but fremy's point that it's not automatic is relevant
<emilio> RESOLVED: Forced colors happens at used value time. Add a note to the spec about implementation

36degrees added a commit to alphagov/govuk-frontend that referenced this issue Jul 9, 2021
When forced color mode was introduced in Chrome 89, the default user agent styles for SVGs were set to `forced-color-adjust: none` in line with the CSS Color Adjustment specification at the time [1]. Unfortunately, this means that using currentColor for stroke and fill in SVGs no longer works as expected in forced color mode.

As per the comment in Chromium bug #1164162 [2]:

> This is the result of one of the recent spec changes. The spec was updated to force colors at used value time rather than computed value time, which means elements that have "forced-color-adjust: none" set (like svg elements) will inherit their non-forced color values, resulting in a different currentcolor used for stroke and fill in this case than you would get if forcing was done at computed value time.
>
> See spec issue resolution for more details: w3c/csswg-drafts#4915

It looks like this has since been flagged as an issue with the CSS working group [3] and the spec has been updated to resolve it [4] but it’s going to take a while before that change is reflected in browsers.

In the meantime, we can explicitly set `forced-color-adjust: auto` on the OGL logo in order for it to correctly inherit the color from the parent [5].

Once Chromium has been updated so that the default UA styles for SVGs use the new `forced-color-adjust: preserve-parent-color` keyword, and traffic to older versions has dropped off, we can then consider removing this.

[1]: https://www.w3.org/TR/2021/WD-css-color-adjust-1-20210520/#forced-color-adjust-prop
[2]: https://bugs.chromium.org/p/chromium/issues/detail?id=1164162#c4
[3]: w3c/csswg-drafts#6310
[4]: https://www.w3.org/TR/2021/WD-css-color-adjust-1-20210616/#forced-color-adjust-prop
[5]: w3c/csswg-drafts#6310 (comment)
36degrees added a commit to alphagov/govuk-frontend that referenced this issue Jul 9, 2021
When forced color mode was introduced in Chrome 89, the default user agent styles for SVGs were set to `forced-color-adjust: none` in line with the CSS Color Adjustment specification at the time [1]. Unfortunately, this means that using currentColor for stroke and fill in SVGs no longer works as expected in forced color mode.

As per the comment in Chromium bug #1164162 [2]:

> This is the result of one of the recent spec changes. The spec was updated to force colors at used value time rather than computed value time, which means elements that have "forced-color-adjust: none" set (like svg elements) will inherit their non-forced color values, resulting in a different currentcolor used for stroke and fill in this case than you would get if forcing was done at computed value time.
>
> See spec issue resolution for more details: w3c/csswg-drafts#4915

It looks like this has since been flagged as an issue with the CSS working group [3] and the spec has been updated to resolve it [4] but it’s going to take a while before that change is reflected in browsers.

In the meantime, we can explicitly set `forced-color-adjust: auto` on the OGL logo in order for it to correctly inherit the color from the parent [5].

Once Chromium has been updated so that the default UA styles for SVGs use the new `forced-color-adjust: preserve-parent-color` keyword, and traffic to older versions has dropped off, we can then consider removing this.

[1]: https://www.w3.org/TR/2021/WD-css-color-adjust-1-20210520/#forced-color-adjust-prop
[2]: https://bugs.chromium.org/p/chromium/issues/detail?id=1164162#c4
[3]: w3c/csswg-drafts#6310
[4]: https://www.w3.org/TR/2021/WD-css-color-adjust-1-20210616/#forced-color-adjust-prop
[5]: w3c/csswg-drafts#6310 (comment)
36degrees added a commit to alphagov/govuk-frontend that referenced this issue Jul 15, 2021
When forced color mode was introduced in Chrome 89, the default user agent styles for SVGs were set to `forced-color-adjust: none` in line with the CSS Color Adjustment specification at the time [1]. Unfortunately, this means that using currentColor for stroke and fill in SVGs no longer works as expected in forced color mode.

As per the comment in Chromium bug #1164162 [2]:

> This is the result of one of the recent spec changes. The spec was updated to force colors at used value time rather than computed value time, which means elements that have "forced-color-adjust: none" set (like svg elements) will inherit their non-forced color values, resulting in a different currentcolor used for stroke and fill in this case than you would get if forcing was done at computed value time.
>
> See spec issue resolution for more details: w3c/csswg-drafts#4915

It looks like this has since been flagged as an issue with the CSS working group [3] and the spec has been updated to resolve it [4] but it’s going to take a while before that change is reflected in browsers.

In the meantime, we can explicitly set `forced-color-adjust: auto` on the chevron SVG in order for it to correctly inherit the color from the parent [5]. This mimics the fix for the OGL logo in the footer made in 850c0b7.

Once Chromium has been updated so that the default UA styles for SVGs use the new `forced-color-adjust: preserve-parent-color` keyword, and traffic to older versions has dropped off, we can then consider removing this.

[1]: https://www.w3.org/TR/2021/WD-css-color-adjust-1-20210520/#forced-color-adjust-prop
[2]: https://bugs.chromium.org/p/chromium/issues/detail?id=1164162#c4
[3]: w3c/csswg-drafts#6310
[4]: https://www.w3.org/TR/2021/WD-css-color-adjust-1-20210616/#forced-color-adjust-prop
[5]: w3c/csswg-drafts#6310 (comment)
36degrees added a commit to alphagov/govuk-frontend that referenced this issue Jul 15, 2021
When forced color mode was introduced in Chrome 89, the default user agent styles for SVGs were set to `forced-color-adjust: none` in line with the CSS Color Adjustment specification at the time [1]. Unfortunately, this means that using currentColor for stroke and fill in SVGs no longer works as expected in forced color mode.

As per the comment in Chromium bug #1164162 [2]:

> This is the result of one of the recent spec changes. The spec was updated to force colors at used value time rather than computed value time, which means elements that have "forced-color-adjust: none" set (like svg elements) will inherit their non-forced color values, resulting in a different currentcolor used for stroke and fill in this case than you would get if forcing was done at computed value time.
>
> See spec issue resolution for more details: w3c/csswg-drafts#4915

It looks like this has since been flagged as an issue with the CSS working group [3] and the spec has been updated to resolve it [4] but it’s going to take a while before that change is reflected in browsers.

In the meantime, we can explicitly set `forced-color-adjust: auto` on the chevron SVG in order for it to correctly inherit the color from the parent [5]. This mimics the fix for the OGL logo in the footer made in 850c0b7.

Once Chromium has been updated so that the default UA styles for SVGs use the new `forced-color-adjust: preserve-parent-color` keyword, and traffic to older versions has dropped off, we can then consider removing this.

[1]: https://www.w3.org/TR/2021/WD-css-color-adjust-1-20210520/#forced-color-adjust-prop
[2]: https://bugs.chromium.org/p/chromium/issues/detail?id=1164162#c4
[3]: w3c/csswg-drafts#6310
[4]: https://www.w3.org/TR/2021/WD-css-color-adjust-1-20210616/#forced-color-adjust-prop
[5]: w3c/csswg-drafts#6310 (comment)
36degrees added a commit to alphagov/govuk-frontend that referenced this issue Jul 16, 2021
When forced color mode was introduced in Chrome 89, the default user agent styles for SVGs were set to `forced-color-adjust: none` in line with the CSS Color Adjustment specification at the time [1]. Unfortunately, this means that using currentColor for stroke and fill in SVGs no longer works as expected in forced color mode.

As per the comment in Chromium bug #1164162 [2]:

> This is the result of one of the recent spec changes. The spec was updated to force colors at used value time rather than computed value time, which means elements that have "forced-color-adjust: none" set (like svg elements) will inherit their non-forced color values, resulting in a different currentcolor used for stroke and fill in this case than you would get if forcing was done at computed value time.
>
> See spec issue resolution for more details: w3c/csswg-drafts#4915

It looks like this has since been flagged as an issue with the CSS working group [3] and the spec has been updated to resolve it [4] but it’s going to take a while before that change is reflected in browsers.

In the meantime, we can explicitly set `forced-color-adjust: auto` on the chevron SVG in order for it to correctly inherit the color from the parent [5]. This mimics the fix for the OGL logo in the footer made in 850c0b7.

Once Chromium has been updated so that the default UA styles for SVGs use the new `forced-color-adjust: preserve-parent-color` keyword, and traffic to older versions has dropped off, we can then consider removing this.

[1]: https://www.w3.org/TR/2021/WD-css-color-adjust-1-20210520/#forced-color-adjust-prop
[2]: https://bugs.chromium.org/p/chromium/issues/detail?id=1164162#c4
[3]: w3c/csswg-drafts#6310
[4]: https://www.w3.org/TR/2021/WD-css-color-adjust-1-20210616/#forced-color-adjust-prop
[5]: w3c/csswg-drafts#6310 (comment)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Closed Accepted by CSSWG Resolution Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. css-color-adjust-1 Current Work
Projects
None yet
Development

No branches or pull requests

9 participants