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-values][css-images] Unit algebra with <flex> in stripes() leads to a contradiction #9667

Open
Loirooriol opened this issue Dec 1, 2023 · 6 comments
Labels

Comments

@Loirooriol
Copy link
Contributor

https://drafts.csswg.org/css-images-4/#stripes

A <flex> is evaluated as a fraction of the total width relative to the total sum of <flex> entries in the function, after subtracting the thickness of any non-<flex> entries (flooring the subtraction result at zero). If the sum of <flex> values is less than 1fr, the result of the subtraction is multiplied by the sum’s value before being distributed.

Suppose a total width of 100px, what should happen with stripes(#000 50px, #111 calc(1fr / 1fr * 50px), #222 1fr)?

  • 1st stripe is a <length> of 50px
  • 2nd stripe is a <length> of calc(1fr / 1fr * 50px) 😓
  • 3rd stripe is a <flex> of 1fr

Then,

  • If we assume that 1fr is not zero, the 2nd stripe is 50px thick, and so we distribute 100px - 50px - 50px into 1fr, so the third stripe is 0px thick. So the final thicknesses are 50px, 50px, 0px, but this is a contradiction because we assumed that 1fr wasn't zero.
  • If we assume that 1fr is zero, the 2nd stripe gets a NaN * px which is censored into 0px at the top-level calculation. So we distribute 100px - 50px - 0px into 1fr, so the 3rd stripe is 50px thick. So the final thicknesses are 50px, 0px, 50px, but this is a contradiction because we assumed that 1fr was zero.

Thus it's a contradiction either way. How to solve it?

@SebastianZ
Copy link
Contributor

How to solve it?

By this note in the definition of <flex>:

<flex> values are not <length>s (nor are they compatible with <length>s, like some <percentage> values), so they cannot be represented in or combined with other unit types in calc() expressions.

Sebastian

@Loirooriol
Copy link
Contributor Author

That refers to calc(1fr + 1px), which is effectively invalid. I'm talking about something else.

@tabatkins
Copy link
Member

Right, whether or not you match a production like <length> only looks at the non-zero entries of its type, and in 2fr / 1fr * 1px the type is {flex: 0, length: 1}, which'll successfully match.

@SebastianZ
Copy link
Contributor

That refers to calc(1fr + 1px), which is effectively invalid.

And so is calc(1fr / 1fr * 50px). The definition basically says that <flex> values cannot be used in calc() expressions.

The contradictory is rather that CSS Values 4 says that <flex> values can be represented in calc().

Also, why is this specific to the stripes() function? Doesn't this issue also apply to Grid then? I.e. grid-template-columns: 50px calc(1fr / 1fr * 50px) 1fr; with a 100px wide element.

and in 2fr / 1fr * 1px the type is {flex: 0, length: 1}, which'll successfully match.

@tabatkins So you suggest the result of the example to be 50px, 50px, 0 due to the two fr units cancelling each other out?

Sebastian

@tabatkins
Copy link
Member

The definition basically says that values cannot be used in calc() expressions.

No, I think you're misreading/misunderstanding.

Flex values are not compatible with lengths; you can't add them together. But you can use flex values in an expression with lengths, so long as you never actually combine it with a length value in a way that uses type addition. So 1fr / 1fr * 1px is completely valid (final type {flex: 0, length: 1}, matches <length>), but 1fr + 1px is invalid (type addition notices each has non-zero types that aren't present in the other, so fails).

So you suggest the result of the example to be 50px, 50px, 0 due to the two fr units cancelling each other out?

That is what I'd naively expect, and it might be reasonable to fix the spec to allow it, yes. I haven't been able to fully think it thru yet, tho.

@Loirooriol
Copy link
Contributor Author

I have been thinking further about this, and I believe I was mistaken, because:

  • Whether 1fr ends up having the same behavior as 0px is irrelevant, <flex> is not being resolved into a length so we aren't actually dividing by zero
  • Only a top-level <flex> in a <color-stripe> ends up behaving as some length. These are just intermediate values so they don't obey https://drafts.csswg.org/css-images-4/#valdef-stripes-flex

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

No branches or pull requests

3 participants