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-grid][css-contain] Clarify that contain:size affects track sizing #4931

Closed
MatsPalmgren opened this issue Apr 9, 2020 · 23 comments
Closed

Comments

@MatsPalmgren
Copy link

Consider the following case:

<div style="display:inline-grid; contain:size;">
  <item style="background:red">Hello Kitty</item>
</div>

My understanding of the CSS Containment spec is that the intent of contain:size is that all size calculations should be done as if the element has no children:
https://drafts.csswg.org/css-contain/#containment-size
Chromium and Gecko agrees that the content-box size in the above case is 0x0, which is correct. I tend to think that the track sizes also should be zero and thus that it should render the same as:

<div style="display:inline-grid; grid:0/0;">
  <item style="background:red">Hello Kitty</item>
</div>

Neither Chromium nor Gecko does that currently, but I intend to fix this in Gecko (bug 1488878).

I can't find any spec text dealing with this case explicitly though, so I would like CSS Grid to clarify that when the Grid container has contain:size the Track Sizing Algorithm should be run as if the container has no items. This will have the effect that any intrinsic track sizes will be zero.

@MatsPalmgren
Copy link
Author

(I've filed a Chromium bug.)

@bfgeek
Copy link

bfgeek commented Apr 9, 2020

I don't believe that is the intent of the containment specification. From the spec:

When calculating the size of the containing box, including when computing its intrinsic size, it must be treated as having no contents.

This is effectively just an early out when computing the intrinsic sizes for an element.

Then, its contents must then be laid out into the containing box's resolved size.

Any layout algorithm should not then change its behaviour after the above step. E.g. these two cases should render the same:

<div style="display:inline-grid; contain:size;">
  <item style="background:red">Hello Kitty</item>
</div>
<div style="display:inline-grid; width: 0px;">
  <item style="background:red">Hello Kitty</item>
</div>

@Loirooriol
Copy link
Contributor

Chromium and Firefox are not interoperable in these cases:

<div style="display: inline-grid; grid-auto-columns: 50px; height: 50px; contain: size; border: 5px solid">
  <div style="background: yellow"></div>
</div>
<div style="display: inline-grid; grid-template-columns: 50px; height: 50px; contain: size; border: 5px solid"></div>

In Chromium, the content area of the grid container is 50px wide, in Firefox it's 0px.

@MatsPalmgren, in https://bugzilla.mozilla.org/show_bug.cgi?id=1488878#c1 you say that what you want to implement is

  1. place items into the grid as usual
  2. run Track Sizing algo but pretend we have no items
  3. calculate the container's size from the track sizes as usual

This seems what Chromium is doing, i.e. step 1 can create implicit tracks, tracks may end up being bigger than 0px in step 2, and this affects the size of the grid container in step 3.

However, according to the CSS Grid spec, once we know the size of the grid container, it's laid out again "for real". So there are more steps:

  1. place items into the grid as usual
  2. run Track Sizing algo, this time taking the items into account

Then I'm not sure why you think that the tracks should be 0px in your example. Do you want to avoid laying the grid again if there is size containment?

@MatsPalmgren
Copy link
Author

When calculating the size of the containing box, including when computing its intrinsic size, it must be treated as having no contents.

This is effectively just an early out when computing the intrinsic sizes for an element.

The "including when computing its intrinsic size" (my emphasis) seems to imply that it affects more size calculations than just the intrinsic size of the box itself. I don't see anything in the spec that supports the idea that it only affects the intrinsic box size.
You can think of the calculation of intrinsic track sizes as an "intrinsic sizing calculation" if that helps since it's based on the intrinsic sizes of the items (the chapter is even named Resolve Intrinsic Track Sizes).

<div style="display:inline-grid; width: 0px;">

Did you forget the height:0? The contain:size spec is pretty clear that the children shouldn't affect the size: "This ensures that the containing box can be laid out without needing to examine its descendants." so clearly you don't want the container to have its height sized by the item.

Anyway, the Containment spec already says that "this does not necessarily make the element zero-sized: properties set on the element itself, such as the columns property or the grid property, continue to be taken into account.". I read "taken into account" there as "run the TSA pretending that the grid container has no items", which is what I suggested in the OP. I don't think there is a way to take the grid properties into account in any other way.
IOW, what I'm suggesting is merely making concrete what the spec is already suggesting as I see it.

@frivoal
Copy link
Collaborator

frivoal commented Apr 10, 2020

My understanding is the same as @bfgeek and @Loirooriol here. The "inculding intrinsic size" bit means that if the layout of any parent of the size-contained element depends in some way on the intrinsic size of that size-contained element, then that input to its layout is the same as if that size-contained element was empty.

For instance, the size of a grid row depends on the intrinsic sizes of the elements in that row. Say you have a column which is sized to min-content, we look at the intrinsic min content size of the elements in the column, pick the largest, size the column that way, and then do the actual layout of the grid items in that column at that width. During that phase, if any of the grid items have size containment, they'll be treated as empty for the purpose of figuring out their min-content size.

However, setting size-containment on the grid itself would not affect the intrinsic size calculation of the grid items.

The "including when computing its intrinsic size" (my emphasis) seems to imply that it affects more size calculations than just the intrinsic size of the box itself.

No, it means that it's both the size of the box in actual layout, and the intrinsic size of the box if requested by its parent, that are calculated as if the box were empty. Not that other unspecified operations (such as track sizing) also treat it as empty. The spec tries to be explicit that once you've done this sizing step, everything else runs normally, with the following statement:

Then, its contents must then be laid out into the containing box's resolved size.


Anyway, the Containment spec already says that "this does not necessarily make the element zero-sized: properties set on the element itself, such as the columns property or the grid property, continue to be taken into account.". I read "taken into account" there as "run the TSA pretending that the grid container has no items", which is what I suggested in the OP. I don't think there is a way to take the grid properties into account in any other way.

For the purpose of finding how big the grid is, yes. Hence the grid in your example being sized to width:0; height:0; But then we do actual layout of the grid, and at that point everything behaves as usual, and so it's track aren't empty.

At least:

  • that's what I meant when I phrased the spec that way
  • doing what you suggest instead doesn't seem necessary to allow the kind of optimizations that size-containment is trying to enable. (to be fair, I don't think it would disable them either.)

That said, if it is not clear (which seems to be the case), the spec should certainly at least be clarified. If we have agreement that the behavior suggested here would be more useful, I suspect we could switch to that, but it's not clear to me that it is.


Chromium and Firefox are not interoperable in these cases:

<div style="display: inline-grid; grid-auto-columns: 50px; height: 50px; contain: size; border: > 5px solid">
  <div style="background: yellow"></div>
</div>

In Chromium, the content area of the grid container is 50px wide, in Firefox it's 0px.

Yeah, in that case, Chromium is right and Firefox is wrong. That is exactly what the note in the spec is about:

Even when the element’s sizing properties are auto this does not necessarily make the element zero-sized: properties set on the element itself, such as the columns property or the grid property, continue to be taken into account.

@frivoal
Copy link
Collaborator

frivoal commented Apr 10, 2020

Chromium and Firefox are not interoperable in these cases […]

WPT has (at least) two tests for that, which Firefox fails:
https://wpt.fyi/results/css/css-contain/contain-size-grid-002.html
https://wpt.fyi/results/css/css-contain/contain-size-grid-003.html

Interestingly, Firefox does pass the corresponding multicol tests:
https://wpt.fyi/results/css/css-contain/contain-size-multicol-001.html
https://wpt.fyi/results/css/css-contain/contain-size-multicol-as-flex-item.html

frivoal added a commit to frivoal/wpt that referenced this issue Apr 10, 2020
@MatsPalmgren
Copy link
Author

The "including when computing its intrinsic size" (my emphasis) seems to imply that it affects more size calculations than just the intrinsic size of the box itself.

No, it means that it's both the size of the box in actual layout, and the intrinsic size of the box if requested by its parent, that are calculated as if the box were empty. Not that other unspecified operations (such as track sizing) also treat it as empty.

This is a fundamental misunderstanding of how Grid layout works. Track sizing isn't "other unspecified operations" unrelated to a grid container's size. It's literally the way you calculate its content-box size, per spec: "The max-content size (min-content size) of a grid container is the sum of the grid container’s track sizes (including gutters) in the appropriate axis, when the grid is sized under a max-content constraint (min-content constraint)." So suggesting that size-containment doesn't affect track sizing makes no sense because if it doesn't then it can't affect the grid container's size either.

To be concrete, here's how Gecko reports "the intrinsic size of the box if requested by its parent". I've highlighted the three salient steps there:

  1. place items into the grid
  2. run the Track Sizing Algorithm (TSA) in the relevant axis
  3. return the sum of the track sizes + gaps

The spec tries to be explicit that once you've done this sizing step, everything else runs normally, with the following statement:

Then, its contents must then be laid out into the containing box's resolved size.

OK, so it seems what you're trying to say then is that contain:size only has an effect when the grid container is sized under a min-/max-content constraint, and has no effect otherwise?

[...] I read "taken into account" there as "run the TSA pretending that the grid container has no items", which is what I suggested in the OP. I don't think there is a way to take the grid properties into account in any other way.

For the purpose of finding how big the grid is, yes. Hence the grid in your example being sized to width:0; height:0; But then we do actual layout of the grid, and at that point everything behaves as usual, and so it's track aren't empty.

I'm guessing "how big the grid is" means "what the content-box size of the grid container is". (please try to use precise terms that are defined in specs or we're going to talk past each other).

doing what you suggest instead doesn't seem necessary to allow the kind of optimizations that size-containment is trying to enable.

Doing what you suggest means that we have to run the TSA twice: once without items to determine the grid container's content-box size and once with items to determine the track sizes to use for layout of the children. Always running the TSA without items, as I suggested in the OP, is an optimization (and a lot simpler to implement since running it once is what we're currently doing).

Yeah, in that case, Chromium is right and Firefox is wrong. That is exactly what the note in the spec is about:

Even when the element’s sizing properties are auto this does not necessarily make the element zero-sized: properties set on the element itself, such as the columns property or the grid property, continue to be taken into account.

Right, but the way you "take the grid property into account" is to run the TSA. So again, there is no other way to implement this but to run the TSA without items (at least under a min-/max-content constraint) and use the track sizes that falls out. If you're thinking of something else then please point to spec text that defines that alternative algorithm.

I can live with doing it twice I guess, if you all think it's important that intrinsic track sizes should be sized normally before laying out the children.

@Loirooriol
Copy link
Contributor

@MatsPalmgren Can you clarify what's your proposal if you don't want to run the TSA without items when sizing the grid container under a min/max-content constraint, and then run the TSA with items when laying it out for real?

In your first comment you say that the track size should be 0, seemingly implying that you only want to run the TSA without items, never with items.

In your last comment you seem to mean that you want to ignore grid (so that you can avoid running the TSA) when sizing the grid container under a min/max-content constraint. And then run the TSA once with items when laying out for real.

So not sure I understand your proposal.

@MatsPalmgren
Copy link
Author

In your first comment you say that the track size should be 0, seemingly implying that you only want to run the TSA without items, never with items.

Right, that's option A.

In your last comment you seem to mean that you want to ignore grid (so that you can avoid running the TSA) when sizing the grid container under a min/max-content constraint. And then run the TSA once with items when laying out for real.

No, I never said grid should be ignored. On the contrary, running the TSA is how you take grid into account. You can run it without items though. Then definite track sizes are still sized normally, but intrinsic track sizes will be zero. So option B (that I described in my last comment) is to run the TSA once without items for calculating the intrinsic content-box size of the grid container, and then a second time with items when "laying it out for real" (so that the final track sizes are sized normally as if contain:size weren't specified). The grid container's intrinsic size would still be taken from the first step though (the first step isn't needed if it has a definite size obviously). So for example:

<div style="display:inline-grid; contain:size; grid:auto 100px / auto 200px">
  <item><div style="width:300px; height:300px"></div></item>
</div>

with option A:
the grid container content-box size is 200px x 100px
the resolved track sizes are 0px 100px / 0px 200px
the item's content-box size is 0px x 0px
with option B:
the grid container content-box size is 200px x 100px
the resolved track sizes are 300px 100px / 300px 200px
the item's content-box size is 300px x 300px

So not sure I understand your proposal.

I've described two different options (so far). I hope they are clear now.

BTW, I'm assuming above that the grid item placement step in the Grid layout algorithm always occurs, also for contain:size. But this isn't at all clear from the CSS Containment spec. In fact, a strict reading of the spec implies that it shouldn't occur: "When calculating the size of the containing box, including when computing its intrinsic size, it must be treated as having no contents."

The "treated as having no contents" implies that implicit tracks should not be created (since there are no items if we treat it as having no contents), for example:

<div style="display:inline-grid; contain:size; grid-auto-rows:100px; grid-auto-columns:100px">
  <item></item>
</div>

Chrome makes the grid container content-box size 100px x 100px, i.e. clearly not treating it as empty when computing its intrinsic size, which contradicts what the spec text currently says.

So the spec needs to say explicitly which parts of Grid layout are supposed to be run with/without items, unless it means all of them.

I don't have a strong opinion on which option to choose. Option B seems to be close to what Chrome is currently doing and that seems to be the behavior you guys prefer, so that's fine with me. It needs to be clearly specified how it's actually supposed to work though, because the current spec text suggests something completely different.

@MatsPalmgren
Copy link
Author

Also, the part about honoring grid etc is mentioned in a Note in the spec. The Conformance section says that notes aren't normative if I read it correctly: "All of the text of this specification is normative except sections explicitly marked as non-normative, examples, and notes."

I assume honoring grid is supposed to be a normative requirement and thus it shouldn't (only) be mentioned in a note.

@frivoal
Copy link
Collaborator

frivoal commented Apr 13, 2020

The definition of intrinsic sizes is explicitly about the min-content size and max-content size, not about track sizes or any other sizable aspect of an box (grid track sizes, multicol column sizes, etc). So by my reading (and by my intent when writing it), the spec calls for finding out the min-content width and height and max-content width and height (if you ever need them) and the width and height of the element as if it were empty, and once you've done that, you do full layout using these sizes. Yes, it does imply that you run the grid track sizing algorithm twice, once with empty tracks (for sizing purposes) and once with actual content (when doing the layout). A possible implementation strategy could be to have a specialized (and simpler/faster) implementation of the track sizing algo that only does track-sizing of an empty grid.

I'm still not understanding how the spec can be seen as ambiguous about that. For example, you said:

In fact, a strict reading of the spec implies that it shouldn't occur: "When calculating the size of the containing box, including when computing its intrinsic size, it must be treated as having no contents."

The "treated as having no contents" implies that implicit tracks should not be created (since there are no items if we treat it as having no contents)

However, to get to this interpretation, you need to ignore the "when calculating …" part of the sentence. When you calculate the size of the box, you treat it as having no content, and therefore do not reserve room for any implicit track. When laying out the grid into that size, you do the full grid layout, with its content, including sizing the tracks correctly, and creating implicit tracks as necessary.

Even if it is not ambiguous, it may still be a bad idea. I don't think it is a bad idea, but we can discuss that.

  • The advantage of switching to "option A" would be that we would only need to size the tracks once, rather than twice. Even with specialized first pass that can only handle empty grids but works faster on those, doing things once is should always be faster than doing them twice.

  • The disadvantage of doing "option A" is that it makes the feature less useful: gird sizes its track the way it does because that's the most useful thing to do for the layout of the grid. While contain:size defines what happens to auto-sized elements, it's largely meant to be used on elements that have a fixed author-supplied size. And regardless of how we end up getting the size we ant to layout into, within that size, calculating the track sizes normally will result in a normal grid layout. Calculating track sizes as if the grid were empty and laying out the grid items within those will result in a worse layout, and that difference is not necessary to realize the benefits expected from size containment.

Anyway, If I understand correctly, you're not necessarily advocating for "option A", merely saying that the spec could be read that way, and want it to be clearer on whether it means A or B.

I remain unconvinced that it can be read to mean option A, but nonetheless, if you have a suggestion of better phrasing to gets unambiguously to option B, it's always better to be clearer.

By the way, the reason why the grid text is in a note is that no additional normative requirement is meant on grid, and this is just an illustration/reminder of how the preceding normative text is meant to be applied to grid. I believe that option A would be special rules for grid, and would need to be normative.

@Loirooriol
Copy link
Contributor

with option A: [...] the item's content-box size is 0px x 0px

The grid area would be 0x0, yes, but wouldn't the item be bigger due to the automatic minimum size? Or would it not apply since we would kind of be treating the auto track sizing function as 0px? On the one hand, I think it's bad if the automatic minimum size forces an item to grow bigger than its grid area. On the other hand, the item being 0x0 also seems bad. So I'm not a fan of option A.

When you calculate the size of the box, you treat it as having no content, and therefore do not reserve room for any implicit track.

@frivoal You don't? So Chromium is wrong?

To summarize this issue, below I list the possibly unclear questions about the interaction of grid and size containment.

When sizing a grid container with size containment under a min/max-content constraint,

  1. Should we run the placement algorithm (creating implicit tracks if needed)?
    Florian says we shouldn't? Chromium does, Firefox does not.
  2. Should we run the track sizing algorithm?
    The spec says so. Chromium does, Firefox just sets the size of the grid container to 0.
  3. If 1 and 2 are affirmative, should tracks take intrinsic contributions of the items into account?
    No, that would defeat the point of using size containment.

When laying out the grid container with size containment into that size,

  1. Should we run the placement algorithm (creating implicit tracks if needed)?
    Yes, we need to know where to place the items in order to display them.
  2. Should we run the track sizing algorithm?
    Yes, we need to know the sizes of the grid areas in order to size the grid items.
  3. If 4 and 5 are affirmative, should tracks take intrinsic contributions of the items into account?
    Yes with option B, not with option A. Chromium and Firefox do it.
  4. If 6 is negative, should the automatic minimum size still apply?
    Maybe not?

@frivoal
Copy link
Collaborator

frivoal commented Apr 17, 2020

When you calculate the size of the box, you treat it as having no content, and therefore do not reserve room for any implicit track.

@frivoal You don't? So Chromium is wrong?

I think so:

  • spec based reasoning: spec says to size the element as if it were empty. implicit tracks with a non-zero fixed min track sizing function would have an impact on the size, and only exist if the element is not empty. Therefore, don't take them into account when calculating the size. (but then when later doing the layout pass, sure, do consider the grid items and do create the relevant tracks).
  • goal based reasoning: if we take the number of elements into account in order to figure out how many implicit tracks we have, and these implicit tracks have a non-zero fixed min track sizing function, then, by applying display:none to grid items, we can change the size of the grid. This would mean that the element is not actually contained, and optimizations based on containment would become incorrect.

So, answers to your numbered questions are:

When sizing a grid container with size containment under a min/max-content constraint,

  1. Should we run the placement algorithm (creating implicit tracks if needed)?
    Florian says we shouldn't? Chromium does, Firefox does not.

No, that would defeat the point of using size containment.

  1. Should we run the track sizing algorithm?
    The spec says so. Chromium does, Firefox just sets the size of the grid container to 0.

Yes. We could switch to no without defeating the point of using size containment, but that would result in a less useful layout.

  1. If 1 and 2 are affirmative, should tracks take intrinsic contributions of the items into account?
    No, that would defeat the point of using size containment.

Agreed.

When laying out the grid container with size containment into that size,

  1. Should we run the placement algorithm (creating implicit tracks if needed)?
    Yes, we need to know where to place the items in order to display them.

Agreed

  1. Should we run the track sizing algorithm?
    Yes, we need to know the sizes of the grid areas in order to size the grid items.

Agreed. We could switch to no without defeating the point of using size containment, but that would result in a less useful layout.

  1. If 4 and 5 are affirmative, should tracks take intrinsic contributions of the items into account?
    Yes with option B, not with option A. Chromium and Firefox do it.

Yes. We could switch to no without defeating the point of using size containment, but that would result in a less useful layout. Also, if authors have a layout which would be resilient to that and want the extra optimization opportunities, they can apply size containment to the grid items.

  1. If 6 is negative, should the automatic minimum size still apply?
    Maybe not?

I don't think 6 should be negative, so ¯\_(ツ)_/¯

@MatsPalmgren
Copy link
Author

The definition of intrinsic sizes is explicitly about the min-content size and max-content size, not about track sizes or any other sizable aspect of an box (grid track sizes, multicol column sizes, etc).

But to calculate the intrinsic size of a grid container you need to calculate its track sizes first, since the Grid spec literally says that its intrinsic size is derived from those. Hence the question of how they should be calculated for contain:size arise.

So by my reading (and by my intent when writing it), the spec calls for finding out the min-content width and height and max-content width and height (if you ever need them) and the width and height of the element as if it were empty, and once you've done that, you do full layout using these sizes.

But the contain:size spec says that it should be treated as empty in more cases than just for intrinsic sizing though:
"When calculating the size of the containing box, including when computing its intrinsic size, it must be treated as having no contents."

If you meant that it should only affect the intrinsic size of the container's box then you need to change it to "When calculating the intrinsic size of the containing box, it must be treated as having no contents." so that it excludes the "when laying out the grid into that size" phase (to use your phrasing).

The ambiguity with Grid layout though is that the track sizes are calculated again during the layout phase and that part of layout is considered an intrinsic sizing step (not the container's intrinsic size, but the track sizes). So I think the Containment spec needs to make it clear that that step is excluded from the "treat the container as empty" condition.

Anyway, If I understand correctly, you're not necessarily advocating for "option A", merely saying that the spec could be read that way, and want it to be clearer on whether it means A or B.

Correct, I claim that the contain:size spec is ambiguous (for Grid at least). I haven't advocated for any particular behavior (so far).

By the way, the reason why the grid text is in a note is that no additional normative requirement is meant on grid, and this is just an illustration/reminder of how the preceding normative text is meant to be applied to grid.

Right, but the problem is that, for a few of the possible interpretations of the spec, it's not just clarifying the preceding text. If we go for the "it should be treated as empty so implicit tracks aren't created" option then yes, in that case it's only a clarifying note. Otherwise, it's not just clarifying but instead modifies/contradicts the preceding text and thus shouldn't be in a note.

@MatsPalmgren
Copy link
Author

MatsPalmgren commented Apr 17, 2020

I think I agree with your answers to @Loirooriol's questions but let me clarify one point to avoid any misunderstanding:

When sizing a grid container with size containment under a min/max-content constraint,

  1. Should we run the placement algorithm (creating implicit tracks if needed)?
    Florian says we shouldn't? Chromium does, Firefox does not.

No, that would defeat the point of using size containment.

This is the wrong way to see it IMO. We should run the placement algorithm, and all other algorithms for that matter, it's just that when we treat the container as empty then we have zero items and thus we don't create any implicit tracks. IOW, when calculating the container's intrinsic size for <container style="...; contain:size">X</container> it's always calculated identically to <container style="...; contain:size"></container> regardless of what the ... expands to.

So the spec changes I would suggest are:

  1. change "When calculating the size of the containing box, including when computing its intrinsic size, it must be treated as having no contents." to "When calculating the intrinsic size of the containing box, it must be treated as having no contents.". Perhaps also add a parenthetical clarification: "(including any pseudo-elements)" at the end.

  2. remove the note that follows that text since it's now redundant and just adds FUD

  3. Change "Then, its contents must then be laid out into the containing box's resolved size." to "Then, its contents is laid out into the containing box's resolved size normally, i.e. contain:size has no effect in this phase."

(3 is needed to clarify that the Resolve Intrinsic Track Sizes step for Grid should not treat the container as empty during layout. (Perhaps there are other cases (multicol? flexbox?) where this also matters, I haven't checked.))

EDIT: let's call this option C, since it's different from option A and B which I presented in #4931 (comment).

@MatsPalmgren
Copy link
Author

BTW, is "containing box" really a good term to use? Isn't "container's box" clearer? Or perhaps "principal box" would be better since it's an already established term.

@Loirooriol
Copy link
Contributor

spec based reasoning: spec says to size the element as if it were empty. implicit tracks with a non-zero fixed min track sizing function would have an impact on the size, and only exist if the element is not empty. Therefore, don't take them into account when calculating the size.

@frivoal Well, but the spec says "When calculating the size of the containing box". The Grid Item Placement Algorithm is not part of the Grid Sizing Algorithm, it's a previous step. So if the size containment is supposed to apply not only during sizing but also during previous steps that can affect sizing, then the spec should probably clarify it.

if we take the number of elements into account in order to figure out how many implicit tracks we have, and these implicit tracks have a non-zero fixed min track sizing function, then, by applying display:none to grid items, we can change the size of the grid. This would mean that the element is not actually contained

It seems to me this would be more like style containment rather than size containment.

My understanding is that size containment is only supposed to prevent the intrinsic size of an element from depending on the size of the contents. But in this case, the existence of implicit tracks wouldn't depend on the layout of the children, only on their computed style.

So I'm not opposed to avoid creating implicit tracks with size containment, but I'm not convinced that's necessary.

This is the wrong way to see it IMO. We should run the placement algorithm

@MatsPalmgren But in practice it doesn't matter, right? The placement algorithm places items, if it behaves as having no contents then there are no items to place and the placement algorithm is no-op.

@frivoal
Copy link
Collaborator

frivoal commented Apr 23, 2020

  1. Change "Then, its contents must then be laid out into the containing box's resolved size." to "Then, its contents is laid out into the containing box's resolved size normally, i.e. contain:size has no effect in this phase."

Sure. That's a reasonable clarification.

Perhaps also add a parenthetical clarification: "(including any pseudo-elements)" at the end.

This too seems like a useful clarification.

  1. change "When calculating the size of the containing box, including when computing its intrinsic size, it must be treated as having no contents." to "When calculating the intrinsic size of the containing box, it must be treated as having no contents.".

That would not work:

If the size-contained grid is inside of a absolutely positioned element, or inside of a float which is itself inside a zero-width div, then when we try to figure out the size of the abspos or of the div, we look at the intrinsic size of its content (the size-positioned grid): the max-content size in the case of the abspos, the min-content size in the case of the float in a zero-width container. This is correctly captured by your phrasing (and also I believe by the one currently in the spec).

However, the effect is not limited to this, and your suggested edit drops the other part:

If a size-contained grid is an ordinary block-level child of an ordinary div, the grid must still be sized as if it were empty, then laid out in that size. For a grid with no gap, fixed-sized track, etc, than would mean a width equal to that of its block container, and a height of 0. This is not calculating the intrinsic size of the grid. It is calculating its size.

My understanding is that size containment is only supposed to prevent the intrinsic size of an element from depending on the size of the contents. But in this case, the existence of implicit tracks wouldn't depend on the layout of the children, only on their computed style.

So I'm not opposed to avoid creating implicit tracks with size containment, but I'm not convinced that's necessary.

When you change the style of the children of the grid to display:none, or to turn them into abspos, or to use grid-row or grid-column to explicitly place them into implicit tracks, you can affect the number of tracks implicit tracks, and if they have a non-zero fixed min track sizing function, this in turn affects the size of the grid even if you ignore them when sizing the tracks. But since the goal of size containment is that whatever happens inside the element has no effect on the size of the element, this cannot be allowed.

@MatsPalmgren
Copy link
Author

the grid must still be sized as if it were empty, then laid out in that size

Well, a box either intrinsically sized, or has a definite size from the style properties, or stretch fit into a definite available size. There are no other cases, hence the part I removed is unnecessary and just adds confusion. Obviously, when the size is definite then whether or not it should be consider to have no contents when calculating that size is irrelevant. So the only case that remains is intrinsic sizing.

Anyway, I believe we agree on the behavior, just not which wording to best describe it.

But since the goal of size containment is that whatever happens inside the element has no effect on the size of the element, this cannot be allowed.

OK, so you're advocating for option C (#4931 (comment)) then, if I understand you correctly?

@css-meeting-bot
Copy link
Member

The CSS Working Group just discussed Clarify that contain:size affects track sizing.

The full IRC log of that discussion <myles> Topic: Clarify that contain:size affects track sizing
<Rossen_> github: https://github.com//issues/4931
<myles> florian: mats palmgren and I were having a long discussion about what the spec currently means. We are coming down to agreeing what's desired, but not what the actual words in the spec say. contain:size says that when you try to figure out the size of an element or its intrinsic size, you treat it as if it has no descendents, then you do layout. He was wondering does this mean you do track sizing of grid with our without descendents?
<myles> florian: AFAIAC, Track sizing for layout, it's not intrinsic sizing. If you have no children, then you have no implicit tracks, then you look at explicit tracks, then you know the grid, and you lay out.
<iank_> q+
<myles> florian: But if there is intrinsic sizing of the tracks, should this be canceled out?
<Rossen_> q?
<myles> florian: Earlier, number of tracks is not described as being sizing
<myles> florian: The conclusion is that no, you don't create implicit tracks for the grid, because that would change the size of the grid. But when you do a layout, you calculate the track size property. We are now agreeing now. But we are disagreeing on whether the words in the spec say that
<myles> florian: If your track sizes have a fixed min number of pixels, then you incorporate it, and do a full layout.
<myles> oriol: Currently in chromium, the contents are taken into account. They are placed in the grid and they can create implicit tracks.
<myles> oriol: This defeats the point of having size containment, since now the size of teh grid container can depend on contents. But the dependency is not on the size of hte contents, but instead their computed style
<myles> oriol: But instead this would be style containment... but I'm fine with what florian is proposing.
<myles> florian: Size-containment means your own size is unaffected by your children. Not that your children's sizes are contained.
<AmeliaBR> Size containment is supposed to prevent intrinsic sizing from affecting parent/siblings. So shouldn't affect internal grid layout beyond the size of the box.
<myles> florian: To achieve that, we need children not to create implicit trakcs
<Rossen_> ack iank_
<fantasai> +1 to AmeliaBR's description
<myles> iank_: I agree with that model. However, we may want to consider changing what size containment means, given container queries we just discussed. Currently, your grid template columns will affect the inline size of your element. In david's proposal, if you have a container query and it can affect some subset of properties, grid template columns can't do that.
<myles> iank_: There are only 2 layout modes that are special here: grid and multicol.
<AmeliaBR> q?
<myles> iank_: So we could change size containment to act more like block and flexbox, and ignore grid template columns. This means that containment queries, if you can style a certain amount of properties, grid template can be one of these properties
<myles> dbaron: I think we're a few steps away from determining whether this is a possibility at all. But it sounds reasonable
<myles> iank_: I worry if we don't consider this soon, we'll start closing off opportunities.
<myles> iank_: This might be a better way to write the spec and avoid this whole problem.
<dbaron> s/reasonable/reasonable. Not sure we're ready to make decisions based on it, but also not sure we want to foreclose it./
<AmeliaBR> q+
<myles> florian: I think this is compatible with the goals. If we do get the ability to do container queries, that could make this restriction worth it. Later, we might also want a stricter kind of containment, if that's valuable
<myles> iank_: I would push back against that. Having one grid+multicol ... people understand what size containment does. It matches that mental model. I don't think we should add unnecessary complexity there.
<myles> florian: Thinking through this, if you have a grid that is a block-level child of whatever's around it, it will be sized with width, and everything isfine. But if its intrinsic size ... [missed]
<Rossen_> ack AmeliaBR
<myles> AmeliaBR: There seems to be a bit of confusion of whether the issue is about which properties affect the calculated size that you're containing to, vs once you've contained that size which features are you restricting. Do these two necessarily have to be the same? Are we allowed to look at the column properties and figure out they determine a minimum size, and say "okay that's the size we're containing to we can figure out just by looking properties on this
<myles> element, no need to look at children"
<Rossen_> q?
<myles> AmeliaBR: But then in another case, the column properties might be auto, or otherwise based on intrinsic size of the child contents, and so in that case the size that would be contained would be dependent on other properties on the element we're containing. When we go to lay out the grid inside that element, can we still lay out that grid based on the children and if the results from laying out the grid is larger than the container size, then we get scrollbars
<myles> florian: The spec say you have to do that. That's what i was trying to say when I wrote it. Mats disagrees that's what it says. Perhaps either TabAtkins or I should rewrite it to make sure it says that. But maybe if container queries happen, this will need updating
<myles> florian: Notice that this is further along on the req track than grid is, so maybe this text should be done in grid instead.
<Rossen_> ack fantasai
<myles> fantasai: I agree with florian. This is the most straightforward way to define it.
<myles> fantasai: Even if we weren't tracking these specs process-wise. It could be called out in contain
<myles> florian: There's a note already.
<myles> fantasai: yes. iank_'s point about wanting grid-template-columns to be changeable is a good one, but if we're not doing that, then if the idea that it doens't create intrinisic tracks is unworkable, we have to put them in tracks somehow, we can't put them all on top of each other
<myles> florian: There are two phases. 1. size 2. lay out. For the first phase, pretend it has no children, don't consider implicit tracks but do consider explicit ones. 2nd phase: Of course we consider implicit tracks.
<fremy> (+1 to proposal)
<myles> fantasai: Proposal: Clarify the contain spec about ignoring children when doing intrinsic sizing, but don't ignore for layout
<myles> fantasai: And open a second issue about whether grid should have g-t-c be ignored for intrinsic sizing, and put it in the grid spec
<myles> iank_: It should go in the containment spec. The min and max content size is affected.
<myles> florian: for multicol as well?
<myles> iank_: Potentially. columns won't affect intrinsic size of multicol.
<myles> florian: What if you say columns: 3 300 column-gap: 300, what's teh benefit of [missed]
<myles> iank_: Inside the container query, you can change the size of the contents, but you can't change the number of children
<myles> iank_: This is a strictly better if we get container queries. Now is the right time to do it.
<myles> Rossen_: I see support in IRC by fremy
<fantasai> s/min and max content/min- and max-content/
<myles> florian: This will also be a change in form controls, which are weird and not completely replaced elements, and are not 0 when they are empty
<myles> florian: I ran into a bug about this. Dropdowns with no children are big enough to not only have the arrow but also have some space where its contents would be
<myles> Rossen_: What is the summary?
<myles> florian: Proposal: Replace what we have in .1 of size containment, where it says [reads]
<fantasai> Kinda discussing 'contain: size' vs 'contain: children' seems like...
<myles> florian: And to say that all elements are .... no. we don't want 0. we still want to fill available width.
<myles> florian: If you're a block and you're size contained, you're supposed to fill your container
<myles> iank_: I agree it should be potentially an exception for replaced elements and non-replaced elements
<myles> Rossen_: Let's take these one by one
<myles> Rossen_: For the contain spec, we are going to add a clarification of ignoring children for intrinsic sizing purposes and not layout
<fantasai> ... were 'contain: size' treats min-content and max-content sizes as `contain-intrinsic-size`, and 'contain: children' pretends there's no children for purpose of intrinsic sizes...
<myles> florian: We're either going to tweak the wording editorially, or we're changing that min-content and max-content width and height are 0
<myles> dbaron: I'm nervous about addressing min content and max content only without also saying what the effects on layout are. Size containment affects both of them.
<myles> florian: There is no effect on layout.
<myles> dbaron: I think there is from one layout model to another. That's correct for grid, but I don't think every layout model lays out that way. For example, block does in one dimension but not the other
<myles> AmeliaBR: How about "for the purposes of determining size, min-content and max-content are 0, but they go back to normal when laying out children?"
<myles> dbaron: I'm trying to think through it again.
<myles> dbaron: don't wait on me.
<myles> Rossen_: It's valid to not resolve on this if we're not ...
<myles> florian: We've uncovered something new and significant. There is a benefit to simplify the definition for the purpose of container queries, then we can go back to github to see what it would be.
<myles> Rossen_: It would be great to consider more than grid in here. Would this ever be possible in tables?
<myles> florian: Size containment does not apply to various table parts
<myles> iank_: Table size containment is broken in many browsers
<myles> Rossen_: let's end here.
<myles> Rossen_: florian, you have lots of feedback here to put into the issue. Let's continue making forward progress there. Feel free to open the grid-related issue if we need to go that way.
<myles> Rossen_: That's everything for this one. Thank you!

@frivoal
Copy link
Collaborator

frivoal commented Oct 7, 2020

Hmm. I accidentally let this sleep for a little too long.

In summary, at this point, I think we have narrowed it down to two possible approaches:

α) Clarification of the current spec, to stay true to its initial intent, which would have you size the element as if it was empty, including explicit grid tracks sized as if they had no element placed in them, and not including any implicit track since they wouldn't be created in the absence of content; then in a second phase, perform layout of the content within the now fixed-size box normally. Specific wording to be tweaked, but it's in the spirit of "solution C".

β) Make contain:size more aggressive, and actually suppress explicit grid tracks as well during the sizing step (but still lay everything normally in phase 2). This isn't really necessary for the purposes of contain:size itself, but if we want to use it as a building block for some kind of container queries thing, that could be useful. Exactly how container queries is going to work (if it ever does) is unclear, but logically, in order to avoid circular definitions, you would not be able to set conditionally by query any properties that can affect the size of the object you're querying. Which means that grid-template can't be something you could change in response to a query about the size of the grid container, unless we made sure that contain:size suppresses its effect on the container’s size.

If we apply the same principles to multicol:

  • the result under α would be that if both column-count and column-width are set, you size as having that many columns of that size (with colum-gaps inbetween); if only column-width is set, you size for 1 column of that size; and if only column-count is set, you size as n-1 times the size of the column gap..
  • the result under β would be that you always size a multicol as an ordinary block.

Typically, size containment isn't used without manually providing a size: For out-of-flow elements, size containment isn't useful, and for in-flow elements, size containment without providing a size results in jumbled / overlapping layouts. So for most uses, the difference doesn't actually matter.

The one case where it would matter is 1D size containment. Having the inline dimension of a block level element be size-contained, without specifying a size manually, would be useful, and could very well serve as a basis for container queries. This is discussed in #1031

That said, as discussed in that issue, it's not clear yet whether whether 1D size-containment + container queries is going to be possible at all.

Unless I am missing something about the usefulness of β with 2D size-containment, I think this leaves us with a few paths forward:

  1. Decide now to do β anyway. It might not be useful if 1D size-containment + container queries turns out to be impossible, but the downside (other than spec and implementation churn) is relatively minor: size-containment without manual size becomes even worse at sizing things, but it was bad in the first place anyway.
  2. Decide now to do α for 2D containment, but keep the question open for 1D containment, if we ever get it to work.
  3. Punt until [css-contain-2] do we need size containment in a single dimension to enable container queries? #1031 is resolved one way or another.

frivoal added a commit that referenced this issue Oct 7, 2020
This is an editorial adjustment, drawing from the non controversial
parts of #4931. This does not on its own resolve that issue.
@frivoal
Copy link
Collaborator

frivoal commented Oct 8, 2020

I've made an exploratory pull request in #5643 (attempts to) implement option α, and can be turned into β with the addition of a single sentence.

@frivoal
Copy link
Collaborator

frivoal commented Dec 16, 2020

This was resolved by merging #5643. The change is applied directly in level 2, and the corresponding change is marked up as a candidate correction in level 1 (to be published soon). Closing.

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

6 participants