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-4] Specify simplification of min() and max() more explicitly #4550

Closed
smfr opened this issue Dec 1, 2019 · 10 comments
Closed

[css-values-4] Specify simplification of min() and max() more explicitly #4550

smfr opened this issue Dec 1, 2019 · 10 comments
Labels
Closed Accepted by Editor Discretion Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. css-values-4 Current Work

Comments

@smfr
Copy link
Contributor

smfr commented Dec 1, 2019

https://drafts.csswg.org/css-values-4/#calc-simplification doesn't say anything specific about min() and max() simplification, but it seems that two types of simplification could happen:

  1. Sort the arguments, as sum/product node children are sorted:
    min(1vw, 1px, 2em,) -> min(2em, 1px, 1vw)

  2. Do partial simplification if possible:
    min(2em, 1px, 3px) -> min(2em, 1px)

@tabatkins WDYT?

@AmeliaBR AmeliaBR added the css-values-4 Current Work label Dec 1, 2019
@AmeliaBR
Copy link
Contributor

AmeliaBR commented Dec 1, 2019

I think both of these are good additions, consistent with the rest of the spec.

@Loirooriol
Copy link
Contributor

How do you sort when you have sums with different units? Like min(1em + 1vw, 1lh + 1px), where em < lh < px < vw, so which argument goes first?

And about partial simplification, it may be problematic with percentages. It may seem min(2em, 1%, 3%) can be simplified to min(2em, 1%), but percentages can resolve to negative values, so actually 3% may be smaller than 1%!

@tabatkins
Copy link
Member

For (1), I don't specify anything about reordering the arguments because I assumed we want to keep the arguments in the order specified. As @Loirooriol points out, you can't generally sort them in any reasonable way; sorting only the arguments that are single values seems low-value and not worth the effort of speccing/implementing/testing, imo.

That said, any sorting we do would be identical to the sorting that is already specified for Sum nodes (as a legacy of the older, simpler calc() where you could always simplify things to a sum of simple values); the simple unit values are in alphabetical order by unit, and the more complex things go at the end in source order. Is it worthwhile applying that sorting to all the commutative operators?

For (2), I could partially apply the min/max function, sure. It would be identical to the combining that goes on within a Sum or Product node. I can go either way on this.

@tabatkins
Copy link
Member

tabatkins commented Feb 21, 2020

You didn't comment further on this, @smfr. Any further thoughts, or do you mind if I just reject these suggestions?


Related: it's unclear exactly what "simplify as far as possible" can mean for the case of a min()/max() with only percentage arguments, such as min(10%, 20%).

We've already established in a previous resolution that, when %s are relative to some other value, you need to wait until they resolve to do any simplification, because in some cases the %s might be relative to a negative value and thus 20% might end up smaller than 10%.

But in some cases we know that the % is relative to a non-negative value, so that isn't true, and we could, theoretically, immediately resolve min(10%, 20%) to calc(10%).

However, this (1) seems silly, as it only applies in the (fairly worthless) case of a min()/max() with only % values in it (not something you'd write manually, tho it could show up due to var() usage), and (2) seems dangerous, as it brings us closer to "percolate arbitrary numeric constraints thru this expression" which I don't want to do.

So I'm planning to make this case clearer in the spec, and mandate explicitly that %s must make the function unresolvable until they resolve against their base value.

In particular, this means that an expression like margin-left: min(10%, 20%) will serialize as min(10%, 20%) in both specified and computed values, and will only simplify away to a single value at used-value time when you can turn those into px values.

/cc @xiaochengh @emilio

@smfr
Copy link
Contributor Author

smfr commented Feb 26, 2020

I don't have strong feelings about this. I'm fine with no changes (other than spec clarification if necessary).

@emilio
Copy link
Collaborator

emilio commented Feb 26, 2020

I think not doing this would be somewhat inconsistent with how all implementations work for cases like color: rgba(0, 0, 0, min(10%, 50%)) or such.

background-size is a bit weirder and seems to be all over the place:

document.body.style.backgroundSize = "min(10%, 100%)"
document.body.style.backgroundSize //  firefox: calc(10%), chrome: min(10%, 100%), webkit: calc(min(10%, 100%))
getComputedStyle(document.body).backgroundSize // firefox / chrome: 10%, webkit: calc(min(10%, 100%))

@Loirooriol
Copy link
Contributor

I think not doing this would be somewhat inconsistent with how all implementations work for cases like color: rgba(0, 0, 0, min(10%, 50%)) or such.

Why? Per https://drafts.csswg.org/css-values/#calc-type-checking, the type of the calculation is «[ "percent" → 1 ]». The percentages don't need to be further resolved in order to calculate the min(10%, 100%). So it can be simplified away at specified-value time.

It's different for background-size. There the percentages are resolved into lengths with respect to the background positioning area, which depends on layout. So it seems to me that min(10%, 100%) shouldn't be simplified until used-value time.

@tabatkins
Copy link
Member

Yeah, I'm talking about things that need to resolve % at used-value time. I just want to stick with "computed" vs "used" as the simplification-boundaries here, and not creating more categories like "technically used-time, but for this particular property we know that 10% will be less than 50% whatever they resolve to, so we could resolve at computed-value time".

@tabatkins
Copy link
Member

Oh sorry, yeah, and specified-value time as well. The three normal value-distinction categories, and nothing fancier than that.

(Like, if we're talking fancy, something like min(-10px, 1em) is resolveable at specified-value time, because you know that the em value will resolve to a non-negative px value. But I don't want to specify that sort of constraint propagation, and I doubt that y'all want to implement it!)

In other words, the simplification rules should just be: if all of the arguments have been resolved to their maximum for the given context, and you can resolve the operation using just the values of the arguments, simplification should replace the function with its result. Otherwise it stays until a later value stage transforms arguments to their final form.

So in colors, %s don't resolve against anything, so a min() consisting of just them can and must be resolved immediately after parsing (the first simplification opportunity dictated by the spec).

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed [css-values-4] Specify simplification of min() and max() more explicitly, and agreed to the following:

  • RESOLVED: min and max get simplified by simple unit values of the same unit we reduce to one instance of each. We also reorder the arguments in the same way that sums reorder. Review math functions for consistency
The full IRC log of that discussion <dael> Topic: [css-values-4] Specify simplification of min() and max() more explicitly
<dael> github: https://github.com//issues/4550
<dael> TabAtkins: Important question is with a min and max funct the spec declares we simplify arg as much as possible and when can fully resolve we replace function with results
<dael> TabAtkins: emilio and smfr wanted to partly implify. Example min(10px,20px,1em) we simplify eagerly to eliminate 20px because there's no way that can be a result. 1em is unclear but when arguements are same unit you can simplify eagerly
<dael> TabAtkins: Do we want to do that is the question
<dael> TabAtkins: IN general I've held only simplify if can befully gotten ride of. But I do simplify sums so ameniable to this level of simplification. not futher. If no objections I'm happy to go ahead and do what emilio wants and allow same unit simple values to be removed from min or max when clearly superfluous.
<dael> TabAtkins: If no obj I'll do that bit and mo more
<TabAtkins> s/ mo / no /
<dael> heycam: For em units it's reasonable to assume non-negative. Case for %?
<emilio> TabAtkins: If we do that we also probably want to define _some_ ordering for those factors (probably the same as for products and sums)
<emilio> Because to simplify fast you want to sort first
<dael> TabAtkins: Depending on property % can be postive or negative or positive only. Can't tell before resolved so need to leave. DOn't want to distinguish cases about when % is against non-negative becuase seems more complex then needed here. Would rather % stay always because there are cases where they can be resolved negative
<dael> heycam: Agree. Technically with 3 % you can get rid of one
<dael> TabAtkins: Yeah but don't want to go to that level
<dael> astearns: emilio comment on IRC
<dael> TabAtkins: He argues we should order factors. Sums serialize in an order. emilio argues to do same for min and max where we eagerly sort arguments.
<dael> TabAtkins: That's fine, we can do that
<dael> TabAtkins: Makes sense since they're binary. If we're doing some simplification I'm fine with that case
<dael> astearns: Other comments?
<TabAtkins> s/they're binary/min and max are equivalent to sum and product/
<dael> smfr: Fine with this. Wanted similarity. Want to look at other math functions coming up to see if need consistency
<oriol> I'm having sound problems. I think this may add more confusion than anything
<oriol> And not much consistent to do it for min/max but not for hypot
<dael> TabAtkins: Other then hypot I don't think anything else. I don't think I want to inter-arg simplify hypot. Step too far.
<dael> TabAtkins: If we have more functions that are commutative binary we should do same thing. Nothing outside min and max fit the bill so far
<dael> astearns: oriol has sound problems but shoulds like agrees to do it as hypot. Think it may cause more confusion
<oriol> I think functions are different than sums because sums are an operator
<oriol> So that argument doesn't convince me
<dael> TabAtkins: Lots of simplification is arbitrary line of where we do it. Saying it's exactly like plus is a fine boundary. Happy to do it with min and max and make that the boundary. If it's essentially plus you simplify. If not you only do it when you can simplify the entire thing away
<oriol> It's even implicit in the notation, + is the usual notation for a commutative group structure in mathematics. It's less clear in min() or max()
<dael> astearns: oriol would you object to the simplifications?
<TabAtkins> min/max are associate+commutative in the same way that + and * are
<TabAtkins> nothing else (including hypot) is
<dael> astearns: TabAtkins can you summarize?
<dael> TabAtkins: Prop: min and max get simplified by simple unit values of the same unit we reduce to one instance of each. We also reorder the arguements in the same way that sums reorder
<oriol> I don't object, but I think this may just add more confusion for authors, so I would prefer to treat functions as black boxes until we have resolved all arguments and can actually call them
<dael> dholbert: Question on that. Is it possible for % to resolve to a negative?
<dael> TabAtkins: Yeah.
<dael> dholbert: So min(2%) isn't resolvable
<dael> TabAtkins: Yeah, we exclude % from that
<dholbert> s/min(2%)/min of two percent values/
<dael> astearns: Also we will look through math functions and make things consistent
<dael> astearns: oriol doens't object, just doesn't think it's useful.
<dael> astearns: Objections?
<dael> RESOLVED: min and max get simplified by simple unit values of the same unit we reduce to one instance of each. We also reorder the arguments in the same way that sums reorder. Review math functions for consistency
<dael> astearns: oriol please continue discussing in the issue

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Closed Accepted by Editor Discretion Commenter Satisfied Commenter has indicated satisfaction with the resolution / edits. css-values-4 Current Work
Projects
None yet
Development

No branches or pull requests

6 participants