[CSS21] Clearance error - hypothetical border edge should be actual border edge (Was: Re: [css2.1] Issue 158 and Issue 178 Resolution)

We know by know, from various recent threads concerning clearance and
margin collapsing, that 9.5.1 is /trying/ to say the following:

   # Computing the clearance of an element on which 'clear' is set is
   # done by first determining the hypothetical position of the element's
   # top border edge within its parent block. <del>This position is
   # determined after the top margin of the element has been collapsed
   # with previous adjacent margins (including the top margin of the
   # parent block).</del>  <ins>This position is the same as the where
   # the actual top border edge would have been if the
   # element had a non-zero top border.</ins>
   # If this hypothetical position of the element's top border edge is
   # not past the relevant floats, then clearance <ins>is introduced
   # and</ins> must be set to the greater of:
   #   1. The amount necessary to place the border edge of the block even
   #      with the bottom outer edge of the lowest float that is to be
   #      cleared.
   #   2. The amount necessary to make the sum of the following equal to
   #      the distance to which <del>these margins</del> <ins>the top
   #      margin of the element and previous adjacent margins</ins>
   #      collapsed when the hypothetical position was calculated:
   #          * the margins collapsing above the clearance
   #          * the clearance itself
   #          * if the block's own margins collapse together: the block's
   #            top margin
   #          * if the block's own margins do not collapse together: the
   #            margins collapsing below the clearance

Firstly, we note the insertion of "clearance is introduced" in the
second paragraph; this is as a result of the resolution of Issue
115 (the clearance paradox)[1].  It's important, because it indicates
that margin collapsing is interrupted.  The calculations which follow
are then based on the fact that this interrupt exists (and that, as a
result, the clearing element may have moved down and the float may have
moved up).  The purpose of the calculations is to then adjust the
resulting position of the clearing element, moving it to the desired place.

Secondly, we note the "hypothetical top border edge position" described
in the first paragraph is merely the position of a hypothetical non-zero
top border.  It's hypothetical in the sense that the clearing element
may not actually have a non-zero top border; it's the position where
such a border would be if it had one.  Of course, if it really does have
one, then the hypothetical edge is the real edge, and the position of
the two is the same.

Thirdly, we can define "hypothetical top border edge position" to
*always* mean this, not just at the point in time when it is calculated
in the first paragraph.  Indeed, it's my belief that this is the border
edge being talked about in Calculation 1.  It's also what's implicitly
being talked about in calculation 2.

Fourthly, it's been established that the term "these margins" in
Calculation 2 refers to the margins being discussed in the paragraph
above.  That is, it refers to the top margin of the clearing element and
previous adjacent margins.

Accordingly, Calculation 2 finally becomes clear: it's saying that
clearance2 is the amount necessary, once clearance is known to be
required and hence margin collapsing has been prevented between boxes
prior to the clearing element and subsequent margins, to return the
hypothetical top border edge to its original position before margin
collapsing was interrupted.  In other words, clearance2 is what stops
the clearing element from moving upwards from its original position.
It's necessary because of the following situation:

 <div style="float:left; width:100px; height:100px"></div>
 <div style="clear:left; margin-top:50px">text</div>

Interrupting the margin collapsing means that the float moves upwards.
Clearance1 would place the clearing element flush with the bottom of
the float; it would move it upwards.  This is typographically
unpleasing.  After all, prior to clearing, it was as low down as it was
for good reason: sensible margin collapsing with surrounding in-flow

How do we know that this really what Calculation 2 is saying?  Well, the
equation is saying:

height of collapsed margin lump resulting from the top margin of the
clearing element and previous adjacent margins

     =     height of margin lump above the clearance
        +  clearance
        +  the clearing element's top margin (if element is self-
           collapsing) or the height of the margin lump resulting from
           collapsing below the clearance (otherwise)

     =     height of margin lump of previous adjacent margins
        +  clearance
        +  distance from the clearance to the clearing element's
           hypothetical top border edge

Which is to say (rephrasing the left-hand side):

distance above the clearing element's hypothetical top border edge to
the top of the collapsed margin lump (prior to introducing clearance)

     =      height of margin lump of previous adjacent margins (after
            introducing clearance, which separates these margins from
            subsequent margins)
        +  clearance
        +  distance from the clearance to the clearing element's
           hypothetical top border edge

The three terms on the right describe the spacings we end up with after
introducing clearance, namely the margin lump above the clearance, the
clearance itself, and the distance from the clearance to the (new
position of the) hypothetical top border edge.  The term on the left is
the distance from the top of the original margin lump (before clearance
was determined as being necessary) to the hypothetical position.

In other words, clearance-2 is precisely the amount needed to return the
hypothetical border edge, after margin collapsing has been interrupted,
to the position it originally occupied.

So that is what the spec is /trying/ to say, with the clearance paradox
and Issue 158 solved.

However, it now becomes clear that what it's trying to say is
nonsense.  Given that we're talking about the hypothetical top border
edge in Calculation 2, it's reasonably safe to assume that it's talking
about the hypothetical top border edge in Calculation 1.  So the whole
thing is talking about hypothetical top border edge.

But what /is/ this hypothetical top border edge?  We're not interested
in some hypothetical edge! We're interested in the *actual* edge, right?
  Well, the hypothetical edge /is/ the actual edge, in the case that an
actual non-zero edge exists (either its own edge, or if not, that of its
first in-flow child that has an edge, etc, according to 8.3.1).  But in
the case that there's no "natural" edge – which is to say, in the case
that the clearing element is self-collapsing – the actual edge position
is that determined in _which used to be the position of a
hypothetical non-zero top border edge, in other words the hypothetical
top border edge_.

So my lingering suspicion[2] that there was a  relationship between the
hypothetical edge and the actual edge was well-founded:  under the old
convention of how to position self-collapsing elements, our
"hypothetical top border edge" wasn't hypothetical at all; it was the
actual, real top border edge position as determined by 8.3.1.

But then in 2007, the convention was changed.[3]  Suddenly, the actual
position of a self-collapsing element was determined using the position
of a hypothetical /bottom/ border edge in (which results in a
different top border position in some cases).  But no-one noticed that
the clearance rules also needed changing to match, no doubt because it
wasn't obvious that they relied on the rules in because
yet again, one part of the spec (9.5.2) tried to re-express some
complicated other part of the spec (8.3.1) in its own words instead of
deferring to that part, and got it wrong.

Had 9.5.2 just said "top border edge" instead of "hypothetical top
border edge as calculated by assuming blah, blah and blah", we wouldn't
have had this problem.

(It now comes as no surprise that using a "hypothetical bottom border"
in 9.5.2 during Bruno Fassino and Tab's experiments in [4] produced more
pleasing results; bottom border was in fact the "right answer".  Having
9.5.2 use a "border" that's not the same as the actual border is
obviously going to result in a silly final position of the clearing
element.  The only reason that tests don't produce total nonsense when
using the incorrect hypothetical border was that its position is always
the same or higher than the actual border position.  Hence the worst
that could happen is that the clearing element is moved down too far:
its "hypothetical" position flush with the bottom of the float and its
actual border position perhaps lower.)

So, to fix the problem, remove all reference to "hypothetical".  We need
to be talking about the real top border edge position in 9.5.2, as
determined by the margin collapsing rules in 8.3.1.

[1] http://wiki.csswg.org/spec/css2.1#issue-115
[2] http://lists.w3.org/Archives/Public/www-style/2010Aug/0090.html
[3] http://lists.w3.org/Archives/Public/www-style/2007Sep/0100.html
[4] http://lists.w3.org/Archives/Public/www-style/2010Jul/0025.html

Anton Prowse

Received on Sunday, 15 August 2010 08:18:39 UTC