W3C home > Mailing lists > Public > www-style@w3.org > August 2010

Re: [css2.1] Issue 158 and Issue 178 Resolution

From: Anton Prowse <prowse@moonhenge.net>
Date: Sun, 15 Aug 2010 08:02:37 +0200
Message-ID: <4C6782FD.3010209@moonhenge.net>
To: www-style list <www-style@w3.org>
CC: "Tab Atkins Jr." <jackalmage@gmail.com>
On 13/08/2010 20:26, Tab Atkins Jr. wrote:
> On Fri, Aug 13, 2010 at 6:59 AM, Anton Prowse <prowse@moonhenge.net> wrote:
>> On 13/08/2010 01:20, Tab Atkins Jr. wrote:
>>> All right, try 2.  I'm pretty certain I have a complete and correct
>>> grasp of margin-collapsing and clearance loaded into my brain right
>>> now.
>>>
>>> Now, none of these changes are normative changes.  They should all
>>> only be clarifications or rephrasings to make things easier to
>>> understand.
>>>
>>> Change 1
>>> --------
>>>
>>> In 8.3.1, sixth bullet point, second sub-bullet point, add the
>>> following after the current text:
>>> "(In other words, for the purpose of positioning the element's top
>>> border edge, the following siblings of the element do not
>>> margin-collapse with the element.)"
>> The idea of introducing an explanatory note mentioning the custom margin
>> collapsing here is a good one.  But I disagree with this wording.
>> Following boxes (note, they're not necessarily siblings of the element)
>> /do/ collapse with the element, but only with its bottom margin.  And
>> the other part to it is that the element is prevented from collapsing
>> its bottom margin with its last child.  Trouble is, the only way to
>> express all that elegantly is to use precisely the device already
>> employed: the temporary introduction of a non-zero bottom border.
>>
>> So I don't think that an explanatory is actually possible, beyond just
>> saying that the purpose of the device is to temporarily restrict certain
>> margin collapsing behaviour.
> 
> Hmm, you're right.  How about this:
> 
> "(In other words, for the purpose of positioning the element's top
> border edge, the element's bottom margin and the margins of any
> following boxes do not collapse with the element's top margin.)"

Better, but it still doesn't explain that the element's bottom margin
doesn't collapse with that of its last in-flow child.  Really, I don't
think there is any better way of describing this than the bottom border
device.  Perhaps simply add a parenthetical to the following sentence in
the spec:

   # 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

   | (and margin collapsing were affected accordingly).

or perhaps
s/affected/recalculated/


>>> Change 2
>>> --------
>>>
>>> In 8.3.1, sixth bullet point, after the last paragraph add the
>>> following example block:
>>>
>>> """
>>> This rule can sometimes result in margins appearing to collapse in
>>> strange ways.  The interactions of the rules is very simple in
>>> practice, though; one must just keep in mind that different sets of
>>> margins may be considered when determining the position of different
>>> elements.
>>>
>>> For example, the following diagram illustrates how one element (the
>>> blue line) positions itself without collapsing its 100px margin-top
>>> with the following red box's 150px margin-top.  This special case only
>>> occurs because the blue line has no content, and thus its top and
>>> bottom margins are self-adjoining.  (Ordinarily you can't detect this
>>> behavior, because a self-adjoining box has no content, background, or
>>> border, but the use of outline or border-image can reveal its position
>>> without changing the behavior of its margins.)
>>>
>>> [[insert picture 1]]
>>>
>>> Note, though, that when calculating the position of the red box, *do*
>>> collapse its margin with the blur box's margin.  The red box simply
>>> positions itself as normal, with its 150px margin collapsing with the
>>> blue box's 100px margin, for a total effective margin of 150px.  Since
>>> the red box pays no attention to the position of the blue box, this
>>> distance is measured from the top of the parent.
>>>
>>> This diagram illustrates a slightly different situation.  It is the
>>> same as before, but now the red box has a margin-top of only 50px.
>>> While the previous diagram didn't actually require the red box to
>>> collapse its margin with the blue box's margin, in this case we see
>>> that the collapse definitely occurs, as the red box positions itself
>>> using its new effective margin-top of 100px.
>>>
>>> [[insert picture 2]]
>>> """
>> To be honest, I don't find these examples enlightening, and I dislike
>> the tone of the first paragraph and the majority of the wording of the
>> others (particularly concerning "positions itself"); although this is
>> subjective, of course.  Also, I don't understand the last sentence of
>> the last paragraph.
> 
> Really?  I find this section to be the most difficult of *everything*
> in margin-collapsing to understand, and the pictures help me to
> understand how the margins are interacting, and make it clear where
> the margins are anchoring themselves.

Oh, it *is* the most difficult of everything.  It's just that the
wording of the examples is all wrong (to me) so it ends up being /less/
clear, not more.  For example:

"the following diagram illustrates how one element (the
blue line) positions itself without collapsing its 100px margin-top
with the following red box's 150px margin-top"

...but the blue element *does* collapse its margin with the red element.
  And when we temporarily introduce the bottom border, the margins don't
collapse; but then the diagram should show 250px of margin if it wants
to show that particular step.

I guess the point is that the only useful diagrams at this part of the
spec are three-step diagrams: the first showing normal collapsing; the
second showing temporary bottom border and a marker indicating top
border position, and the third showing normal collapsing again, but this
time with the marker overlying the margin lump at the same vertical
position as it is in the second step.


> As to the last sentence of the last paragraph, I agree it's confusing.
>  How about removing it, and then *after* the picture, inserting a new
> paragraph:
> 
> "Note the margin behavior here.  In the previous example, the red
> box's margin was larger than the blue box's margin, so although the
> two margins collapsed when positioning the red box, it was
> indistinguishable from the red box's margin simply ignoring the blue
> box entirely.  In this example, because the red box's margin is
> smaller, we see that it does indeed collapse with the blue box's
> margin, so that the red box is positioned as if it had a 100px top
> margin."

In general this wording is much better IMO; it doesn't try to
distinguish margins where they can't be distinguished.  However, the "it
does indeed collapse" creates a distinction where none exists; it did
indeed collapse in the previous example too....

On the whole, I think just one example and (three-step) diagram is
sufficient for this part.


>>> Change 3
>>> --------
>>>
>>> In section 9.5.2, at the end of the paragraph starting "Computing the
>>> clearance of an element...", delete the last sentence of the paragraph.
>>>
>>> Replace it with:
>>>
>>> """
>>> To determine the hypothetical position, collapse the top
>>> margin of the clearing element with preceding adjoining margins per the
>>> margin-collapsing rules in section 8.3.1, as if the element does not
>>> have clearance. (Note: Only use the *preceding* adjoining margins - in
>>> particular, for the purpose of determining the hypothetical position,the
>>> top margin of the clearing element does not collapse with the margins of
>>> its children or its own bottom margin.)  Call the resultant margin the
>>> "hypothetical top margin".
>>> """
>> The clause "as if the element does not have clearance" is unnecessary,
>> because we don't yet know whether it has clearance.  I think you mean to
>> say to assume clear:none.
> 
> Right, I did indeed mean that.  (I hate that the two phrases aren't the same...)

Yeah, me too.  We (somewhat carelessly) talk about "floats", but it's
not so easy to talk about "clears".  I tend to use "clearing element"
but I can't say I like it much.


>> The whole paragraph is basically saying that the hypothetical top border
>> edge position really is the position of a hypothetical non-zero top
>> border, right?  Then can't we just actually say that (which would also
>> avoid the problem I raised in the first half of [1]), and leave it at
>> that?  Why is further/round-about explanation necessary?
> 
> Hmm, yeah, that would work great too.  Good catch.
> 
> 
>> (Note that, in this clear:none phase, the position of the hypothetical
>> top border edge is not necessarily the same as the /actual/ top border
>> edge position as calculated in 8.3.1.6.2.  I still don't have insight
>> into whether that's relevant; superficially it isn't since the latter
>> has no bearing on margin collapsing or clearance.)
> 
> Hm, in what situations are they different?  I'm not immediately seeing anything.

This lies at the very heart of the spec ambiguity problem surrounding
clearance.  Now that I've finally untangled what the spec is /trying/
to say, it's obvious that what it's trying to say is wrong (or at least
misleading).  I'll follow up on this later today – possibly in a new
thread, since it's not precisely Issue 158 (which was concerned with an
unclear description of margins in Calculation 2).


>>> Change 4
>>> --------
>>>
>>> In section 9.5.2, replace the second step of the clearance algorithm with:
>>>
>>> """
>>> 2. The size of the clearing element's top margin (possibly collapsed
>>> with other margins, as detailed earlier in this section) minus the sum
>>> of:
>>>  * the margins collapsing above the clearance
>>>  * if the block's own margins collapse together: the block's top
>>> margin, by itself
>>>  * if the blocks' own margins do not collapse together: the margins
>>> collapsing below the clearance
>>> """
>>
>> Did you mean to use your term "hypothetical top margin" here?
> 
> Yup.  I wrote too much after introducing the term in Change 3, and
> then forgot to use it here to clarify the length used.
> 
> 
>> Just to make sure I understand what's being proposed: in calculations 1
>> and 2, we're assuming that clearance has been introduced and hence that
>> some margin collapsing is disrupted, as per 8.3.1.  (All we're doing by
>> the time we've reached this stage is figuring out how much to "stretch"
>> the clearance.)  The value calculated in the second calculation is:
> 
> Yes, these calculations only occur if the hypothetical position
> doesn't clear the float, thus establishing that clearance must be
> added.
> 
> 
>> value = hypothetical top margin
>>            - margin lump above clearance
>>               - element's top margin OR margin lump below clearance(*)
>>
>> (*) to which the element's top margin was a contributer
>>
>>
>> I need to revisit Bruno's example, but I think we desperately need to
>> add an explanation of why clearance calculation 2 is necessary, ie what
>> the relationship is between the quantities involved.  This is a
>> different issue from Issue 158 though.
> 
> It's a difficult case to construct on the fly (I need to go dive back
> through my mail to find the example that dbaron constructed), but
> calculation 2 is only relevant when the float moves upward due to the
> clearing element's top margin uncollapsing with its previous in-flow
> sibling's bottom margin.  In all other cases calculation 1 will always
> be greater.

Yeah, David's example suffices to demonstrate the situation.  Indeed,
this is what Calculation 2 is for.  I note here that I really liked what
you did in an earlier post,[1] where you replaced the equation in
Calculation 2 with a simple wording explaining what the end result is
(much like how Calculation 1 is handled):

   > * The amount necessary to place the top border edge of the block
   > even with the previously computed hypothetical position of the top
   > border edge of the element.  (Informative Note: This is necessary to
   > handle the case where the float moves due to the element's top
   > margin no longer collapsing with previous margins.)

(This is assuming – reasonably, I think – that that's what the equation
in Calculation 2 really is trying to say.)  It also probably wants to
say "border edge", not "previously computed hypothetical position of
border edge"; more on this in my upcoming post and below.

As to why I like this approach: the problem with having an equation
rather than a statement of intended result is that you then have to
worry about whether the equation is correct (which is precisely what got
us into this mess in the first place)....  And seeing as the spec
doesn't require us to know the actual clearance value at any point, I
don't see any need to fuss about with equations at all.

I would probably modify the Informative Note slightly, to say:

   | This is necessary to prevent the clearing element from itself moving
   | upwards in the case where the float moves upwards due to the
   | clearing element's top margin no longer collapsing with previous
   | margins.

and then we may or may not wish to give an actual example.


>> Note that this proposal doesn't address the other issue from this
>> thread, of what "border edge" means in clearance calculation 1.
> 
> Right, I haven't hit that yet.  I'm pretty sure it means exactly what
> it says, though, as dbaron noted - the actual border edge of the
> block, after margins have uncollapsed.

Me too!

> If it was referring to the
> hypothetical border edge, then the example slightly further down about
> negative clearance wouldn't make any sense.  (Going off of the
> hypothetical border edge, which is 4em below the border edge of the
> first paragraph, the clearance should be 2em.  But that doesn't make
> any sense.  Going off the actual border edge, which is 7em below the
> border edge of the first paragraph after you uncollapse the margins,
> the clearance should be -1em like the example says, which makes the
> element flush with the bottom of the float as intended.)

No, this example merely reveals how one interpretation of Calculation 2
leads to nonsense: namely it shows that clearance isn't the distance
from the hypothetical border edge (at the time of its calculation) from
the bottom of the float.  (Specifically, that particular interpretation
fails to take account of the fact that certain margin collapsing is
prevented when clearance is introduced.)

> I'd be interested in seeing an ambiguous case, but this is the only
> interpretation that makes any sense at all as far as I can tell.

Well, I'm assuming – as you agreed above – that by the time Calculation
2 is performed, margins have already been uncollapsed.  Now, the
hypothetical edge no longer even exists in any sense by this time, at
least not without rewriting the paragraph in which it is introduced so
that it says that the hypothetical edge is *always* the position of a
hypothetical non-zero top border edge rather than just at the moment in
time when it is initially calculated.  But let's just assume that
reasonable definition and proceed.  In the example we're considering,
this hypothetical edge is the same as the actual edge and so there's no
difference in whether we use one or the other.  However, there /will/ be
a difference when the clearing element is self-collapsing; see my
upcoming post.

Thus we can't write off the use of the hypothetical edge just yet.


>>> Change 5
>>> --------
>>>
>>> In section 9.5.2, after the paragraph starting "Clearance is
>>> introduced...", add the following example block:
>>>
>>> """
>>> Note: Clearance, once introduced, takes up permanent space on the
>>> page.  In particular, elements other than the cleared element may have
>>> their position directly affected by it.  For example, if the clearing
>>> element is empty and has self-adjoining margins, a following sibling's
>>> margin may collapse through it.  The sibling will then also use the
>>> clearance to position itself, as the following diagram illustrates:
>>>
>>> [[insert picture 3]]
>>> """
>> Although I don't like the wording, I do agree that this note is
>> worthwhile, since the phrase "Clearance is introduced as spacing above
>> the margin-top of an element" is not accurate.  There *is* no margin top
>> if that margin is involved in collapsing; there's only a faceless margin
>> lump.
> 
> I think that's a valid interpretation, but not a necessary one.  I
> always interpret collapsed margins as being top or bottom margins of
> particular boxes.  It just may be that two boxes share the same blob
> of spacing when their margins are collapsed.

I strongly disagree, and I think this informalism is one of the root
causes of so much confusion about margin collapsing and clearance.
Nowhere does the spec refer to a collapsed margin lump and try to
distinguish an individual margin, and I'm very keen to ensure that this
doesn't creep in.  Chapter 8 does talk about margin area boxes, and it's
fundamentally flawed when it does so, since the margin-level box model
doesn't hold when margins collapse (but holds well for inline-level
elements and for elements that establish block formatting contexts,
since there's no margin collapsing for them).

As I said earlier in this thread, the informalism can certainly be
useful; we all use it all the time, I'm sure.  Firebug uses it too.
However, I challenge you to draw me a diagram showing the final
rendering of the following example (with margin collapsing occurring),
with each element's "box model" areas indicated:

<div style="border-bottom:1px solid"></div>
<div id="tricky" style="margin-bottom:20px">
	<div style="margin:10px 0"></div>
</div>
<div style="border-bottom:1px solid; margin-top:30px"></div>

Specifically, I want to see the box model for the "tricky" element,
including the relationship between its border box position (as
determined by 8.3.1.6.2) and its 20px bottom margin.  ;-)

Unsurprisingly, Firebug struggles with visualizing self-collapsing
elements too....


>>  What your diagram helps to show – although I strongly dislike the
>> representation of the two top margins as distinct entities rather than
>> as one entity with ruler distances marked –
> 
> It would be more confusing to illustrate it as such, I think, as the
> blue element first positions itself *without* collapsing with the red
> box's margin.  The red box does then collapse its own margin with that
> of the blue box, but that's irrelevant for this particular example.

Indeed.  The only change that's needed is to remove "margin-top:50px"
and just write "50px" (not in blue).  The distance is correct; it's
distinguishing that distance as being the margin-top of the blue element
that's wrong.


>> is that clearance is
>> introduced as "spacing" which prevents the lump that results from the
>> collapsing of the margins preceding the element from then going ahead
>> and itself collapsing with the lump that results from the collapsing of
>> subsequent margins.  It's as if, when the clearing element is first
>> encountered, the canvas is cut horizontally after the first margin lump,
>> and an elastic strip sewn in. Then margin-collapsing life carries on as
>> normal except that margins aren't allowed to collapse upwards across the
>> strip.  Then the strip is stretched by the calculated clearance amount.
> 
> I don't understand your example.  ^_^

I don't know how else to explain it in words, since that model is pretty
much an exact representation of what's happening.  (To be fair, I guess
it's not the canvas that's cut; rather, it's the content area of the
element establishing the containing block of the clearing element.)


>> I think the note should just try and say that, rather than talk about
>> specific elements having their positions affected.  Clearance is just
>> interruption of margin collapsing; it's nothing mysterious.
> 
> It's not just interruption of margin collapse, though.  It interrupts
> collapse, *and* introduces additional non-margin spacing.

Precisely.  Hence the elastic strip: zero-width when clearance is zero,
stretched downwards when clearance is positive, and stretched upwards
when clearance is positive.

However, the spacing itself is irrelevant.  All that really matters is
that margins can't collapse through it (even when the spacing is zero).


> I personally originally interpreted clearance as only affecting the
> positioning of the cleared element.  Learning that the clearance can
> directly affect non-cleared elements was a revelation.

Well, not so much...

<p style="clear:left>text</p>
<p>More text</p>

If the clearing paragraph is moved downwards due to the presence of a
float, we wouldn't expect the second paragraph _not_ to move with it.

The same logic applies when the first paragraph is empty; the second
paragraph collapses its top margin with the first, but also needs to be
moved down by the clearance spacing else it might remain next to the
float, which would be silly (and noticeable if it had out of flow
children).  Clearance wouldn't be particularly useful if children or
following elements of a clearing element weren't also somehow moved down
past the float.

This also illustrates why the informalism discussed above is dangerous.
When I wrote
>> the phrase "Clearance is introduced as spacing above the
>> margin-top of an element" is not accurate.  There *is* no margin top
>> if that margin is involved in collapsing; there's only a faceless
>> margin lump.
I was referring to the following situation:

<div style="clear:both; margin-top:0">
	<p style="margin-top:20px">text</p>
</div>

In the presence of floats, clearance is introduced as spacing above the
div... but introduced at 20px above the div's top border edge (at the
top of the margin lump), not 0px above the div's top border edge.  So
even the spec gets itself in trouble with this informalism, and AFAICT
this was precisely the issue which caused you difficulty.


[1] http://lists.w3.org/Archives/Public/www-style/2010Jun/0576.html

Cheers,
Anton Prowse
http://dev.moonhenge.net
Received on Sunday, 15 August 2010 06:04:45 GMT

This archive was generated by hypermail 2.3.1 : Tuesday, 26 March 2013 17:20:30 GMT