Re: [CSS2.1] Margin-collapsing rules in 8.3.1 don't match reality

Tab Atkins Jr. wrote:
> Test case in question:
> http://test.csswg.org/source/contributors/microsoft/incoming/AdjacentMarginsTestCase.htm
> (ignore the fact that the code is slightly malformed - it doesn't
> affect this case).
> 
> Reproduction of the code in question:
> 
> 
> <body style="border:5px solid purple; width:200px;">
>   <div style="height:1em; background:blue;"></div>
>   <div style="margin:1em 0 2em; outline:1px solid orange;"></div>
>   <div style="height:1em; background:green;"></div>
> </body>
> 
> (The first and third <div>s are only there to help illustrate the
> boundaries of the second <div>'s margin box - they play no real part
> in this example.)
> 
> The second <div> here has a margin-top of 1em and a margin-bottom of
> 2em.  It's self-adjoining, so its bottom margin collapses with its top
> margin.  Per spec, this should mean that the top margin basically
> becomes 2em, and the <div> itself should then be flush with the green
> box.
> 
> All implementations do something else, though - the <div> has 1em of
> space above it, and 1em of space below it.  This is easy to explain as
> a partially-collapsed margin - the bottom margin collapses with the
> top margin as much as it can (up to the actual size of the top
> margin), and then the rest stays below the element.

UA behaviour seems to reflect the spec.  I don't see how you're deciding
that the div should be flush with the green box.

When margins collapse, we end up with a margin "lump".  Informally, we
can often point to it and "distinguish" the individual margins of the
various boxes involved, since many cases are fairly trivial.  (It's not
formally correct to do so, though.)  Our difficulty arises when a box is
self adjoining, since our informal approach no longer works.  It's
impossible to distinguish the top margin from the bottom margin in such
a situation, which is why we find it difficult to define the "position"
of such a box.  To solve this, 8.3.1.6 introduces the following
construction:

   # If the top and bottom margins of a box are adjoining, then it is
   # possible for margins to collapse through it. In this case, the
   # position of the element depends on its relationship with the other
   # elements whose margins are being collapsed.
   #   * If the element's margins are collapsed with its parent's top
   #     margin, the top border edge of the box is defined to be the same
   #     as the parent's.
   #   * Otherwise, either the element's parent is not taking part in the
   #     margin collapsing, or only the parent's bottom margin is
   #     involved. The position of the element's top border edge is the
   #     same as it would have been if the element had a non-zero bottom
   #     border.

Bullet point 2 says that to define the position of the element's top
border edge, temporarily do the collapsing again but this time with a
non-zero bottom border on the element.

In the test case you present, temporarily doing the collapsing with a
non-zero bottom border on the second div, we find that the position of
the bottom border edge of that div is 20px below the body's content area
top edge, or equivalently, 10px below the blue div.  (Really, we should
be talking about position on the canvas, but it's good enough to use the
closes ancestor that doesn't participate in the collapsing.)  Thus, when
we do the collapsing for real, that's still where the bottom border edge
is defined to be.  Hence the orange outline at precisely that position
with respect to the canvas.

> This also helps to explain the behavior of the cases in the previous
> mail.  The simplest way to explain it appears to be that the clearance
> takes up actual space *separate from* and above the margin of the <b>
> element (and which margins are not allowed to collapse through), and
> then the <u>'s top margin collapses upwards with the <b> in the same
> way that it does for the test case in this message.

That's *exactly* what clearance is, according to the spec.  It isn't
margin; rather, it's like some kind of impermeable space.  I haven't yet
looked too carefully at that set of test cases yet, though, because they
involve 'clear' and that's a different ball game, depending as it does
on the unclear rules for determining the hypothetical position of the
top border edge when deciding whether clearance is needed.

I'll state here that I can't git rid of my nagging feeling that there's
some deep relationship between the determination of the bottom border
edge position in 8.3.1.6.2 and the particular choice of margins to
collapse in the determination of the hypothetical top border edge
position in 9.5.2, although superficially they don't seem to be related.
  (Note that in the former calculation, it used to be the /top/ border
edge that was calculated, but that was changed.[1]  And in the latter
calculation, you and Bruno Fassino were iterating towards changing the
spec to using a temporary bottom border edge to define which margins
collapse.[2])


> Here's a more involved version of the earlier test-case:
> 
> <body style="border:5px solid purple; width:200px; padding: 0 0 3px;">
>  <div style="height:100px; width: 25px; float: left; background:blue;"></div>
>  <div style="outline:1px solid orange; margin:20px 0 0; clear: left;"></div>
>  <div style="outline:1px solid green;  margin:30px 0 0;"></div>
>  <div style="outline:1px solid red;    margin:40px 0 0;"></div>
> </body>
> 
> Same code, but now we have *three* empty elements with outlines.  The
> orange clearing element has 20px of top margin, and so it gains 80px
> of clearance.  The green element has 30px of top margin, so 20px of it
> collapses upward into the orange's top margin, with the remaining 10px
> below the orange.  The red has 40px of top margin, so 20px of it
> collapses with the orange's margin, 10px with the green's margin, and
> 10px left over between it and the green.
> 
> This pretty clearly demonstrates that margins collapse only partially,
> and that clearance can affect multiple elements after the clearing
> element.

Again, I'm not really sure by what you mean by "partial margin
collapsing".  There's no such concept as portions of a margin being
collapsed with some other margin; there are just lumps of margin
resulting from margin collapsing, and the position of the various boxes
is defined in 8.3.1.


[1] http://lists.w3.org/Archives/Public/www-style/2007Sep/0046.html
[2] http://lists.w3.org/Archives/Public/www-style/2010Jul/0529.html

Cheers,
Anton Prowse
http://dev.moonhenge.net

Received on Friday, 6 August 2010 12:56:52 UTC