Skip to content

[css-color-4] Specified value for color when calc() is used #8318

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

Closed
weinig opened this issue Jan 16, 2023 · 19 comments
Closed

[css-color-4] Specified value for color when calc() is used #8318

weinig opened this issue Jan 16, 2023 · 19 comments

Comments

@weinig
Copy link
Contributor

weinig commented Jan 16, 2023

With the addition of more specificity for the specified value of colors that just went in (thanks @svgeesus!), one thing that I would like to be explicitly specified is whether calc() should be preserved through specified value serialization.

For example, take:

    let test = document.createElement("div")
    test.style.color = "rgb(calc(100), 255, 255)"

    console.log(test.style.color)

In Safari and Firefox (I have not tested anything else), this logs rgb(100, 255, 255), seemingly resolving the calc(). (See https://bug-250325-attachments.webkit.org/attachment.cgi?id=464424 for a live test case). This is inconsistent with other properties (like say, width), and the way calc() is specified (see #8290 (comment)).

My proposal would be to have colors match other properties and perverse the minimal calc(). So, for the example above, I would expect the right serialization to be rgb(calc(100), 255, 255).

I can see some argument that legacy colors have had this behavior long enough and the required conversions from hsl() to rgb() would make the rules inconsistent in some places, so, as an alternative to always requiring preservation, I think requiring it for all non-legacy colors would be a good option as well.

@svgeesus
Copy link
Contributor

The basic answer is "simplify as much as you can at each stage (specified, computed, used) and then serialize what you've got", with the caveat that if the tree simplifies down to a plain numeric value it's serialized with a calc() around it if it's a specified value (to maintain clamping behavior).

That seems fairly clear (and implies that Safari and Firefox are wrong here and should change). I can add some examples of serializing specified and computed values using calc to CSS Color 4 and 5, but the normative reference would be CSS Values.

The part about maintaining clamping behavior is less clear. If I have

rgb(127 255 0 / calc(75% + 75%))

does the specified value serialize as rgb(127 255 0 / calc(100%)) or rgb(127 255 0 / calc(150%))? I would have assumed early clamping of the over-range alpha value.

@svgeesus svgeesus added css-color-4 Current Work css-values-4 Current Work labels Jan 17, 2023
@svgeesus
Copy link
Contributor

svgeesus commented Jan 17, 2023

In Safari and Firefox (I have not tested anything else)

Chrome does the same (test)

@Loirooriol
Copy link
Contributor

https://drafts.csswg.org/css-values/#calc-range

Clamping is performed on computed values to the extent possible, and also on used values if computation was unable to sufficiently simplify the expression to allow range-checking. (Clamping is not performed on specified values.)

@svgeesus
Copy link
Contributor

@svgeesus
Copy link
Contributor

OK I will add an example showing a calc() with an unclamped single value. But any normative clarification belongs in CSS Values 4.

@tabatkins tabatkins removed the css-values-4 Current Work label Apr 6, 2023
@tabatkins
Copy link
Member

Untagging from Values 4, since everything should be well-defined there.

If we end up needing to do something special for calcs in legacy color functions, we will need a Values edit, so tag it back in that case.

@svgeesus svgeesus self-assigned this Apr 6, 2023
@cdoublev
Copy link
Collaborator

cdoublev commented Apr 7, 2023

the required conversions from hsl() to rgb() would make the rules inconsistent in some places

Do you (all) mean that math functions should not be preserved when converting HSL to RGB? An alternative would be to serialize the HSL color when it contains math functions.

@svgeesus
Copy link
Contributor

Leaving this open because of the open question regarding serializing a specified hsl() value that contains a calc().

@cdoublev
Copy link
Collaborator

cdoublev commented May 10, 2023

Minor precision: the question is also about serializing a specified hwb() (which is not legacy) that contains a calc(), ie. it is about all sRGB functions because they must be converted to rgb().

@svgeesus
Copy link
Contributor

svgeesus commented Jul 5, 2023

Tagging Agenda+ to get discussion on serializing calc-containing hsl() and hwb()

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-color-4] Specified value for color when calc() is used.

The full IRC log of that discussion <fantasai> emilio: Clamped at specified value time in the past, unsure if we can change. Not sure about hsl() etc.
<fantasai> emilio: but we may want something special for rgb()
<fantasai> emilio: might be able to change what spec requires, but also not super excited about it
<fantasai> emilio: all browsers are interoperable right now on the weird thing
<fantasai> TabAtkins: No strong opinion, but in some cases impossible to resolve calc() until later time
<fantasai> TabAtkins: current spec rules define that
<fantasai> TabAtkins: I'm OK to define earlier resolution behavior for certain color functions
<fantasai> TabAtkins: but suggest take it back up once there's a concrete proposal for what to do
<fantasai> TabAtkins: given Chris isn't here, would prefer to have a proposed resolution prepared

@svgeesus
Copy link
Contributor

svgeesus commented Aug 23, 2023

Summarizing current browser behavior when serializing specified values:

  1. calc not preserved in legacy rgb(). Over-range values clamped in specified value. test 1
let test = document.createElement("div");
test.style.color = "rgb(calc(255), 127, 255)";
console.log(test.style.color);
test.style.color = "rgb(calc(100 * 5), 127, 255)";
console.log(test.style.color);

"rgb(255, 127, 255)"
"rgb(255, 127, 255)"

  1. calc not preserved in legacy hsl() because it is serialized as rgb(). Over-range values clamped in specified value. test 2
let test = document.createElement("div");
test.style.color = "hsl(90, calc(100%), 50%)";
console.log(test.style.color);
test.style.color = "hsl(90, calc(100% + 50%), 50%)";
console.log(test.style.color);

"rgb(128, 255, 0)"
"rgb(128, 255, 0)"

  1. calc not preserved in hwb() because it is serialized as rgb(). Over-range values clamped in specified value. test 3
let test = document.createElement("div");
test.style.color = "hwb(90 calc(30%) 70%)";
console.log(test.style.color);
test.style.color = "hwb(90 calc(30% * 2) calc(70% * 2)";
console.log(test.style.color);

Result per CSS Color 4 sample code (see live test) is [0.3, 0.3, 0.3] which in integer precision legacy rgb() is

"rgb(77, 77, 77)"
"rgb(77, 77, 77)"

NOT INTEROPERABLE Chrome follows the spec on normalizing over-range W and B while Firefox and Safari give an odd result:

"rgb(77, 77, 77)"
"rgb(96, 96, 96)"

@svgeesus
Copy link
Contributor

Modern syntax rgb() seems to behave the same as legacy (test modern rgb).

Modern syntax hsl() seems to behave the same as legacy (test modern hsl).

@svgeesus
Copy link
Contributor

Proposed resolution: For historical reasons, early resolution of calc(), where it resolves down to a single value, in both legacy and modern rgb() and hsl(), and in hwb, and clamping of over-range values, for serializing specified values.

@tabatkins Would that require an 'except as over-ridden by other specifications' in Values 4?

Note that the combination of early resolution and early clamping also deals with annoyances like Inf(test 4):

let test = document.createElement("div");
test.style.color = "rgb(calc(255) 127 255)";
console.log(test.style.color);
test.style.color = "rgb(calc(1 / 0) 127 255)";
console.log(test.style.color);

"rgb(255, 127, 255)"
"rgb(255, 127, 255)"

@svgeesus
Copy link
Contributor

@tabatkins ping ahead of this week's call for the values-4 question.

@astearns @atanassov Hoping we can resolve this week, as we didn't quite get to this item last week.

@tabatkins
Copy link
Member

I'd probably add something in V&U saying that some contexts perform "simplification" at specified-value time. Would just be a one-liner somewhere, won't really affect what Color has to say.

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-color-4] Specified value for color when calc() is used, and agreed to the following:

  • RESOLVED: Accept the proposed resolution with the examples included
The full IRC log of that discussion <chris> q+
<astearns> ack chris
<emeyer> chris: I have a proposed resolution in the issue
<emeyer> …Go with what’s implemented
<emeyer> …If calc() resolves to a single value, you get that value without the calc() wrapped
<emeyer> …clamp() resolves to the clamped value
<emilio> q+
<astearns> ack emilio
<emeyer> emilio: Want to clarify that I think the second example is wrong
<emeyer> chris: Yes, you’re right; oops
<emeyer> emilio: Otherwise seems fine to me
<dbaron> I think 1/0 should be +inf, no?
<emeyer> TabAtkins: This is fine with me
<emeyer> astearns: Comments or objections?
<TabAtkins> 1/0 is definitely inf
<emilio> nvm
<emeyer> (silence)
<TabAtkins> https://drafts.csswg.org/css-values-4/#css-infinity
<emeyer> RESOLVED: Accept the proposed resolution with the examples included

@svgeesus
Copy link
Contributor

I see in WPT that parsing/color-computed-hsl.html lacks any calc tests although parsing/color-computed-rgb.html does have them.

@cdoublev
Copy link
Collaborator

cdoublev commented Sep 28, 2023

I am sorry but, can you please clarify one last time if (simplified) math functions should appear in the serialization of specified non-sRGB color values?

test_valid_value("color", "lch(calc(50 * 3) calc(0.5 - 1) calc(20deg * 2) / calc(-0.5 + 1))", "lch(100 0 40 / 0.5)");

https://github.com/web-platform-tests/wpt/blob/7953d2cd55b9977e0dc86cfef191a01508a795c3/css/css-color/parsing/color-valid-lab.html#L101

edit: never mind, it is implied in 15.1. Serializing alpha values (ie. math functions should be preserved in non-sRGB color functions and the above WPT tests is wrong)

For example an alpha value which was specified directly as 120% would be serialized as the string 1. However, if it was specified as calc(2*60%) the declared value would be serialized as the string calc(1.2).


I hope it is fine if I add the corresponding tags for the following (in serialize a math function, I guess):

I'd probably add something in V&U saying that some contexts perform "simplification" at specified-value time. Would just be a one-liner somewhere, won't really affect what Color has to say.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

7 participants
@tabatkins @weinig @svgeesus @Loirooriol @cdoublev @css-meeting-bot and others