w3ctag / design-reviews

W3C specs and API reviews
Creative Commons Zero v1.0 Universal
318 stars 55 forks source link

CSS calc-size() function #955

Open dbaron opened 1 month ago

dbaron commented 1 month ago

こんにちは TAG-さん!

I'm requesting a TAG review of the CSS calc-size() function.

The CSS calc-size() function is a CSS function similar to calc(), but that also supports operations on exactly one of the values auto, min-content, max-content, fit-content, stretch, or contain. This allows transitions and animations to and from these values (or mathematical functions of these values), as long as the calc-size() function is used on at least one of the endpoints of the transition or animation to opt in.

Further details:

martinthomson commented 1 month ago

@hober, @LeaVerou, @plinss, and I discussed this and we have some brief feedback, some of which is really questions.

We have several concerns with the design of this function:

dbaron commented 1 month ago
martinthomson commented 2 weeks ago

do you think having the calc-size() opt-in is too unreadable to be the only opt-in, or do you also think it's too unreadable to be one of the choices for opting in?

Yeah, this is really the crux of the problem that we're also grappling with. We note that CSS met recently and resolved on a separate opt-in mechanism. The remaining question we have is whether the calc-size() wrapper is necessary in light of that.

dbaron commented 2 weeks ago

My current thinking is that I'd like to do the following:

I think there are two reasons to want to keep calc-size():

  1. it's architecturally not really possible (at least cleanly) to have CSS animations that produce intermediate values that aren't representable in CSS. (mix() provides a future mechanism that makes this at least more palatable than it is today albeit still not ideal, but it's not yet implemented anywhere as far as I know.)
  2. The extensible web manifesto gives a number of reasons that we should bias towards exposing the mechanisms underlying things unless we have reasons not to do so; I don't think there's sufficient reason not to expose calc-size() here (even if there is good reason to suggest an alternative for a key set of use cases). (Along these lines, at the CSS face-to-face last week @kizu mentioned having non-animation use cases for calc-size().)
LeaVerou commented 2 weeks ago

(Writing this comment on my own, but from what I recall about our consensus last time this was brought up)

I think there are two reasons to want to keep calc-size():

  1. it's architecturally not really possible (at least cleanly) to have CSS animations that produce intermediate values that aren't representable in CSS. (mix() provides a future mechanism that makes this at least more palatable than it is today albeit still not ideal, but it's not yet implemented anywhere as far as I know.)
  2. The extensible web manifesto gives a number of reasons that we should bias towards exposing the mechanisms underlying things unless we have reasons not to do so; I don't think there's sufficient reason not to expose calc-size() here (even if there is good reason to suggest an alternative for a key set of use cases). (Along these lines, at the CSS face-to-face last week @kizu mentioned having non-animation use cases for calc-size().)

Both of these arguments make the point that intermediate values should be representable in CSS. However, no-one proposed they should not be! Our concern was about introducing a new function to do this whose only purpose seems to be implementation convenience. There does not seem to be any author-facing reason that justifies introducing a distinct calc-size() syntax over simply using calc(). We listed several issues earlier that make the DX calc-size() quite confusing for authors. None of these issues are present when simply reusing calc() for this.

We think that reusing calc() even with constraints about the number of distinct intrinsic size keywords that can be valid within it would be a far better path forwards for authors: No new function to learn, and they would likely never even hit the limitation. The current state is that no intrinsic size keywords are allowed in calc(), so allowing one but no more than that seems like a direct improvement, and leaves the path open for supporting more in the future.

From our perspective, it seems that the only argument against reusing calc() with a limit of one intrinsic keyword max is theoretical purity (that the limitation should be clear from the syntax), which as you know, is at the bottom of the priority of constituencies.

tabatkins commented 1 week ago

First, I dispute that the signaling value of calc-size() can be ignored. A calc-size() is very specifically not a number and can't be used in places where numbers can; it's an intrinsic size usable only in a few specially-allowed places. This is distinct from other specialized uses of calc(), like their use in RCS with channel keywords, where the value takes some context from its surroundings but is afterwards just an ordinary number.

This also comes with a usability benefit, in that because there are behavior differences in layout algorithms based on what sizing keywords you're using, it's of some value to authors to ensure that it's clear and obvious which keyword it is being adjusted. Having it pulled out as the first argument of calc-size() accomplishes this.

Relatedly, it's just plain valuable to know that the value is an intrinsic size, of any sort; having that behavior switch hidden in an arbitrarily-complex calc() isn't ideal. (It also would mean that we could no longer define that calc() is a <length-percentage>; it would only be so conditionally, based on the absence of such a keyword.)

Second, I explained why a separate function, and not just "keywords in calc()", was useful back in the CSSWG thread that introduced this, in direct response to your comments in that thread, @LeaVerou.

If I ignore the ones related to interpolation (largely moot now), and put the signaling value to the side as well, the big remaining reason from that thread is that percentages can have intrinsic behavior, but they already have well-defined and interoperable behavior in calc() which will not smoothly interpolate. That is, if 100% ends up cyclic, interpolating from 100% to 0 will "behave as auto" for the entire duration of the transition, and then suddenly snap to 0 at the end. With calc-size() you can instead get smooth interpolation behavior from any starting size, regardless of what it is, simply by putting it as the first argument.