[csswg-drafts] [css2][css-flow][css-sizing] How do min/max block sizes affect bottom margin collapse with last child? (#12218)

Loirooriol has just created a new issue for https://github.com/w3c/csswg-drafts:

== [css2][css-flow][css-sizing] How do min/max block sizes affect bottom margin collapse with last child? ==
This is the relevant text in CSS2: https://drafts.csswg.org/css2/#collapsing-margins

> bottom margin of a last in-flow child and bottom margin of its parent if the parent has [auto](https://drafts.csswg.org/css2/#valdef-height-auto) computed height

It doesn't check min-height nor max-height, but my understanding is that they are checked via https://drafts.csswg.org/css2/#min-max-heights (CSS2 didn't properly distinguish between computed and used values)

> The following algorithm describes how the two properties influence the [used value](https://drafts.csswg.org/css2/#computed-value) of the [height](https://drafts.csswg.org/css2/#propdef-height) property:
> 
>  1.   The tentative used height is calculated (without [min-height](https://drafts.csswg.org/css2/#propdef-min-height) and [max-height](https://drafts.csswg.org/css2/#propdef-max-height)) following the rules under ["Calculating heights and margins"](https://drafts.csswg.org/css2/#Computing_heights_and_margins) above.
>  2.   If this tentative height is greater than [max-height](https://drafts.csswg.org/css2/#propdef-max-height), the rules [above](https://drafts.csswg.org/css2/#Computing_heights_and_margins) are applied again, but this time using the value of max-height as the computed value for [height](https://drafts.csswg.org/css2/#propdef-height).
> 3.    If the resulting height is smaller than [min-height](https://drafts.csswg.org/css2/#propdef-min-height), the rules [above](https://drafts.csswg.org/css2/#Computing_heights_and_margins) are applied again, but this time using the value of min-height as the computed value for [height](https://drafts.csswg.org/css2/#propdef-height).

Supporting this interpretation is the fact that https://drafts.csswg.org/css2/#collapsing-margins has a this example:

> The bottom margin of an in-flow block box with a [height](https://drafts.csswg.org/css2/#propdef-height) of [auto](https://drafts.csswg.org/css2/#valdef-height-auto) **and a [min-height](https://drafts.csswg.org/css2/#propdef-min-height) of zero** collapses with its last in-flow block-level child’s bottom margin if the box has no bottom padding and no bottom border and the child’s bottom margin does not collapse with a top margin that has clearance.

There wouldn't be a need to mention "min-height of zero" if this wasn't a requirement.

Undermining the interpretation there is the fact that another case does mention `min-height` is mentioned in the definition of another case for adjoining margins:

> top and bottom margins of a box that does not establish a new block formatting context and that has zero computed [min-height](https://drafts.csswg.org/css2/#propdef-min-height), zero or [auto](https://drafts.csswg.org/css2/#valdef-height-auto) computed [height](https://drafts.csswg.org/css2/#propdef-height), and no in-flow children

```html
<!DOCTYPE html>
<style>
.wrapper { display: inline-block; vertical-align: top; border: 5px solid; margin-bottom: 10px }
.test { outline: 5px dotted magenta; }
.test::before { content: ""; display: block; width: 50px; height: 20px; margin-bottom: 30px; background: cyan }
</style>
<div class="wrapper"><div class="test" style="min-height:  0px"></div></div>
<div class="wrapper"><div class="test" style="min-height: 20px"></div></div>
<div class="wrapper"><div class="test" style="min-height: 21px"></div></div>
<div class="wrapper"><div class="test" style="min-height: 40px"></div></div>
<div class="wrapper"><div class="test" style="min-height: 60px"></div></div>
<br>
<div class="wrapper"><div class="test" style="max-height:  0px"></div></div>
<div class="wrapper"><div class="test" style="max-height: 19px"></div></div>
<div class="wrapper"><div class="test" style="max-height: 20px"></div></div>
<div class="wrapper"><div class="test" style="max-height: 40px"></div></div>
<div class="wrapper"><div class="test" style="max-height: 60px"></div></div>
```

|Gecko, Blink, [Servo#36322](https://github.com/servo/servo/pull/36322) | WebKit, Servo |
| - | - |
| ![](https://github.com/user-attachments/assets/3928dcef-c576-4c51-9f5b-0b2683b08636) | ![](https://github.com/user-attachments/assets/a37c95e1-c603-45ff-a2f9-c0425ea528e4) |

Gecko and Blink do not collapse the bottom margin with the last child when min/max-height force a different final height. WebKit and Servo ignore min/max-height, but I want to change Servo (https://github.com/servo/servo/issues/36321), since it doesn't really make sense to collapse margins which aren't even even overlapping.

Another interesting case is when height gets constrained by both min-height and max-height:

```html
<!DOCTYPE html>
<style>
.wrapper { display: inline-block; vertical-align: top; border: 5px solid; margin-bottom: 10px }
.test { outline: 5px dotted magenta; }
.test::before { content: ""; display: block; width: 50px; height: 20px; margin-bottom: 30px; background: cyan }
</style>
<div class="wrapper"><div class="test" style="max-height: 0; min-height: 10px"></div></div>
<div class="wrapper"><div class="test" style="max-height: 0; min-height: 19px"></div></div>
<div class="wrapper"><div class="test" style="max-height: 0; min-height: 20px"></div></div>
<div class="wrapper"><div class="test" style="max-height: 0; min-height: 21px"></div></div>
<div class="wrapper"><div class="test" style="max-height: 0; min-height: 30px"></div></div>
```

| Gecko, Blink, [Servo#36322](https://github.com/servo/servo/pull/36322) | WebKit, Servo |
| - | - |
| ![](https://github.com/user-attachments/assets/b8b24029-14cf-475d-bf7b-19c74318c289) | ![](https://github.com/user-attachments/assets/b192d3ed-0787-4578-9940-c24223067bbe) |

Is it expected to only collapse in the `max-height: 0; min-height: 20px` case since `height: auto` would result in 20px, even though `height: 20px` wouldn't collapse?

The situation gets extra complex due to CSS Sizing introducing intrinsic keywords that can be used in min/max-height. For example, should margins collapse with `height: 0px; min-height: max-content` or `height: 100px; max-height: max-content`? Should these keywords include the child margin?

| Gecko | WebKit | Blink | Servo, [Servo#36322](https://github.com/servo/servo/pull/36322) |
| - | - | - | - |
| ![](https://github.com/user-attachments/assets/83967e2e-abe0-4746-9bfd-b4d5cdf55d29) | ![](https://github.com/user-attachments/assets/975ff872-1987-493a-babb-aef9c633b2fd) | ![](https://github.com/user-attachments/assets/6e24ee28-dd00-4867-b54a-4520286a7a78) | ![](https://github.com/user-attachments/assets/b2bff6d0-4b7f-4798-a6b5-90333f1f3bbe) |

No browser collapses the margin, but
 - Gecko: doesn't support intrinsic keywords in min/max-height
 - Webkit: doesn't support intrinsic keywords in min-height. In max-height they include the margin.
 - Blink: intrinsic keywords in min/max-height don't include the margin.
 - Servo: intrinsic keywords in min/max-height include the margin.

Note it's somewhat circular:

 - The intrinsic block size should presumably only include the child margin if it isn't collapsing (if it's collapsing, the margin acts as belonging to the parent instead of the child, see https://drafts.csswg.org/css2/#normal-block).
 - To know whether the margin is collapsing, presumably we need to compare the final block size with the intrinsic one (if we want to take min/max into account)
 - The final block size depends on the intrinsic block size


Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/12218 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Wednesday, 21 May 2025 06:21:24 UTC