W3C home > Mailing lists > Public > public-css-testsuite@w3.org > November 2013

Re: Issue with margin-collapse-clear-012.htm and margin-collapse-clear-013.htm

From: Řyvind Stenhaug <oyvinds@opera.com>
Date: Sat, 9 Nov 2013 02:57:32 +0100
Message-ID: <CAAx851tvhD=6KcZzLgPxEwJd+-v7rNSfUjUzXGYCgf7gUOjAAA@mail.gmail.com>
To: Public CSS test suite mailing list <public-css-testsuite@w3.org>
(Accidentally replied only to sender)

---------- Forwarded message ----------
From: Řyvind Stenhaug <oyvinds@opera.com>
Date: Sat, Nov 9, 2013 at 2:52 AM
Subject: Re: Issue with margin-collapse-clear-012.htm and
margin-collapse-clear-013.htm
To: Robert Hogan <robhogan@gmail.com>


On 11/07/2013 08:23 PM, Robert Hogan wrote:

> <div id="parent">
> <div id="float" style="float:left; height: 100px; width: 100px;
> background-color:blue;"></div>
> <div id="self-collapsing-with-clearance" style="clear: both;
> margin-top: -40px; margin-bottom:40px;"></div>
> <div id="following-sibling">Text</div>
> </div>

Margin collapsing and clearance is a problematic area, and I didn't
follow all the spec discussions, so I may have missed something, but
I'll give it a shot.

> Per the spec, the only behaviour I can understand is :
>
> - The margin-top of -40px pulls the self-collapsing block up to a
> starting position 40px above the float.

This might be a little inaccurate, though it doesn't matter much. To
compute the clearance, we need to determine the "hypothetical position
of the element's top border edge" (CSS2 9.5.2) as if 'clear' had been
'none'. This technically depends on whether #parent has some extra
styling (if not, the top margins of #parent and
#self-collapsing-with-clearance will collapse and the hypothetical
position would coincide with the top edge of the float, not 40px
above). But either way, the hypothetical position is not past the
float. So clearance is introduced, which stops #parent's and
#self-collapsing-with-clearance's top margins from collapsing with
each other.

> - Then clearance is applied and in order to clear the float we
> calculate clearance of 140px which places the border-top of the
> self-collapsing block flush with the bottom of the float.

Right. To calculate the size of the clearance we need to know the
position of #self-collapsing-with-clearance's top border edge. To do
that, we look at what it would have been if the bottom border had been
non-zero (CSS2 8.3.1), which would keep its margins from collapsing
with each other. Clearance will be added below #parent's top content
edge, and then #self-collapsing-with-clearance's top margin will be
added below that before we arrive at its top border edge. So we need
140px clearance so that this ends up as 140px + (-40px) = 100px which
is just past the float.

> - Now we collapse the margin-top and margin-bottom together to get a 0px margin.
> - We now place following-sibling below the self-collapsing block.

Yes, now we are placing #following-sibling, and we don't need to know
the position of the #self-collapsing-with-clearance block's top border
anymore. So we look at the actual, collapsing margins, not the margins
that would have been "if the bottom border had been non-zero".

> Since we have a 0px margin following-sibling has to be placed directly
> below the float.

No, that's the thing. We have now computed the clearance, it was
140px. Now we add the collapsed 0px margin and get 140px. So
#following-sibling's top border edge will be 140px below #parent's top
content edge.

> I say this because I don't understand why we would calculate 140px
> clearance from the top of the float, when we ought to calculate it
> from 40px above the float in order to place the block flush with the
> border bottom of the float.

It sounds like you might be thinking about this a bit backwards.
Margins are added after the clearance, not the other way around (CSS2
9.5.2: "acts as spacing above the margin-top of an element"). Anyway,
the non-collapsed -40px margin isn't part of this calculation, the
collapsed one is.

A closing comment: Even though non-collapsing margins would give
identical behavior in the case above, they really do collapse. This
can be seen by e.g. giving #following-sibling a -30px top margin. If
-40px and 40px had not collapsed, this would have moved "Text"
upwards:
from 140px - 40px + collapse(40px, 0px) = 140px - 40px + 40px = 140px
to 140px - 40px + collapse(40px, -30px) = 140px - 40px + 10px = 110px
But it actually stays at the same position, since all three margins collapse:
from 140px + collapse(-40px, 40px, 0px) = 140px + 0px = 140px
to 140px + collapse(-40px, 40px, -30px) = 140px + 0px = 140px

--
Řyvind Stenhaug
Opera Software ASA

On Thu, Nov 7, 2013 at 8:23 PM, Robert Hogan <robhogan@gmail.com> wrote:
> HI Alan,
>
> On 6 November 2013 23:36, Alan Gresley <alan@css-class.com> wrote:
>>
>>
>> I would say that they are not collapsing but more overlapping of the margin-top and margin-bottom since the border boxes are not aligned vertically.
>>
>
> As Bruno pointed out the behaviour of the margins in
> self-collapsing-with-clearance seems to be covered by
> http://www.w3.org/TR/CSS2/box.html#collapsing-margins: "Two margins
> are adjoining if and only if: [..] both belong to vertically-adjacent
> box edges, i.e. [..] 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."
>
> It's hard to get past that statement - the margins of a
> self-collapsing box collapse together.
>
> Bruno also pointed out
> http://www.w3.org/TR/CSS2/box.html#collapsed-through which says: "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." I think that's what
> accounts for the behaviour you are seeing with regard to the
> positioning of the border box of self-collapsing blocks.
>
> The question is how we apply both of these rules to the case where we
> have a negative margin top and the margins collapse to zero:
>
> <div id="parent">
>   <div id="float" style="float:left; height: 100px; width: 100px;
> background-color:blue;"></div>
>   <div id="self-collapsing-with-clearance" style="clear: both;
> margin-top: -40px; margin-bottom:40px;"></div>
>   <div id="following-sibling">Text</div>
> </div>
>
> Per the spec, the only behaviour I can understand is :
>
> - The margin-top of -40px pulls the self-collapsing block up to a
> starting position 40px above the float.
> - Then clearance is applied and in order to clear the float we
> calculate clearance of 140px which places the border-top of the
> self-collapsing block flush with the bottom of the float.
> - Now we collapse the margin-top and margin-bottom together to get a 0px margin.
> - We now place following-sibling below the self-collapsing block.
> Since we have a 0px margin following-sibling has to be placed directly
> below the float.
>
> I say this because I don't understand why we would calculate 140px
> clearance from the top of the float, when we ought to calculate it
> from 40px above the float in order to place the block flush with the
> border bottom of the float.
>
> Hopefully someone will have the patience to show me where I'm going
> wrong in this interpretation!
>
> THanks,
> Robert
>
Received on Saturday, 9 November 2013 01:58:01 UTC

This archive was generated by hypermail 2.4.0 : Friday, 20 January 2023 19:58:20 UTC