Description
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 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 of the height property:
- The tentative used height is calculated (without min-height and max-height) following the rules under "Calculating heights and margins" above.
- If this tentative height is greater than max-height, the rules above are applied again, but this time using the value of max-height as the computed value for height.
- If the resulting height is smaller than min-height, the rules above are applied again, but this time using the value of min-height as the computed value for 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 of auto and a 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, zero or auto computed height, and no in-flow children
<!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 | WebKit, Servo |
---|---|
![]() |
![]() |
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 (servo/servo#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:
<!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 | WebKit, Servo |
---|---|
![]() |
![]() |
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 |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
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