- From: Anton Prowse <prowse@moonhenge.net>
- Date: Thu, 26 Aug 2010 01:18:16 +0200
- To: www-style list <www-style@w3.org>
- CC: Bruno Fassino <fassino@gmail.com>, fantasai <fantasai.lists@inkedblade.net>
On 25/08/2010 17:47, Bruno Fassino wrote: > I've not been able to follow all the latest details of this > discussion, anyway I've two naive questions. > > On 08/23/2010 03:40 PM, fantasai wrote: >> >> # 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 and its 'clear' property had been 'none'.</ins> > > > Is "top" in the above last line intended? If yes, I must have missed > something, since I thought the discussion was moving toward using > "bottom" there. It was... but then the pieces of the puzzle finally fitted together, and I was able to see what 9.5.2 was trying to say and what the WG was hoping it says. It turns out that what 9.5.2 is trying to say is: "Use some notion of hypothetical top border position to determine if the clearing element is past the relevant floats. If clearance is necessary then the appropriate margin collapsing is inhibited, and the clearance is set to the greater of the amount necessary to put the real top border flush with the bottom of the float and the amount necessary to put it where the hypothetical border position was (to cover the case where inhibiting the margin collapsing causes the float to move upwards)." What the WG was hoping it says is the same as the above but with the proviso that there be no unexpected loss of margins and no unexpected whitespace. Trouble is, as test cases show, the notion of hypothetical top border position used in the spec (namely, temporary top border) doesn't satisfy the WG's goal... and nor does the notion we were contemplating in which a temporary bottom border is introduced. This deters us from both these notions. So we need to go back to first principles to understand what we're trying to achieve. A good first step is to ignore the possibility of a self-collapsing clearing element. Then we all intuitively know what we would like the hypothetical border top position to be: it's merely the "obvious"/real border top position. It makes complete sense to use this to determine if clearance is necessary, and the case for using some other notion would have to be boldly fought, since any author would be likely to say, "hang on, that browser's introduced clearance when it's patently obvious it wasn't necessary" (or vice versa). We violate the WG's goal, even for "easy" cases, if we use any other notion. (We were getting ahead of ourselves in the earlier threads when trying to choose between other, different notions; we should have already dismissed them all on the basis of much easier test cases than the ones we were considering.) As you noted, the difficulty for my preferred notion – real top border position – arises when the clearing element is self-collapsing, because the spec's convention for this position is non-intuitive, which in turn makes deciding upon the desired clearance behaviour rather difficult. (Although we're already winning, because we've confined any ugly renderings to atypical, self-collapsing cases.) Let's see what happens in your test case: > On 08/23/2010 7:23 PM, Anton Prowse wrote: >> >> I suggest the >> following change to resolve both this issue and Issue 158: >> >> # 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>as if the value of its 'clear' property >> # had been 'none', as per the rules in 8.3.1.</ins> >> # >> # If this hypothetical position of the element's top border edge is >> # not past the relevant floats, then clearance<del>must be</del> >> #<ins>is introduced and margins collapsed anew according to the rules >> # in 8.3.1. >> # >> # Then the amount of clearance is</ins> set to the greater of: >> # >> # 1. The amount necessary to place the<ins>top</ins> border edge of >> # the block even with the bottom outer edge of the lowest float >> # that is to be cleared. >> # 2.<del>The amount necessary to make the sum of the >> # following...</del> >> #<ins>The amount necessary to place the top border edge of the >> # block at the previously-computed hypothetical position.</ins> > > > I remember we already discussed the idea to use full (normal) margin > collapsing to compute the hypothetical position, and we saw this > produces "unexpected" results in some cases, like this one: > > <div style="background: yellow">before</div> > <div style="background: lime"> > <div style="float: left; height: 50px; width: 100px; > background:blue"></div> > <div style="clear: left; margin-bottom: 100px"></div> > </div> > <div style="background: yellow">next</div> > > Unless I'm missing something, your formulation still produces an > "unexpected" result here. Indeed, it's a nasty result. I analyzed this test case in detail in [1], but allow me to quickly summarize that again: First, assume clear:none. The float's parent P is self-collapsing, so by 8.3.1.6.2, P's top border position is 100px below the bottom of "before". The clearing element C is also self-collapsing, and so by 8.3.1.6.1, C's top border position is the same as P's. C's top border position is not past the float and so we introduce clearance. C no longer collapses its top margin with P's top margin. We recompute the layout, and we're in that funny case where the float moves upwards. Specifically, the float is now flush with the bottom of "before". For C's current position, 8.3.1.6.2 applies and we find that it is also flush with the bottom of "before". _We observe that inhibiting the margin collapsing moved both P's and C's top border position upwards._ The clearance is then the greater of 50px (the amount needed to move C's top border downwards to below the float) and 100px (the amount needed to move it to the previously-calculated hypothetical position). Hence clearance is 100px, C's bottom margin extends a further 100px downwards, and "next" is 200px below the bottom of "before". Ugly; we've pushed "next" down too far. In my original analysis, I claimed this to be a consequence of the WG's 2007 decision to use bottom border to determine the top border of the lime div P (through 8.3.1.6.2). Had top border been used instead, as the spec used to require, then P's hypothetical top border position would have been directly below "before", as would the top of the float and the hypothetical position of C's top border. Clearance would still be introduced – but it wouldn't affect the top border position of the lime div, and so the float would stay where it was, the clearance would be 50px and C would "move down" to just below the float, with "next" 100px below that, as we might have liked. However, now that I have more insight into the issue, I see that it the situation is more subtle. Firstly, equally nasty layouts occur with the pre-2007 convention for top border position of self-collapsing elements. Sure, it fixes the test case above, but what about the following one: <div style="background: yellow">before</div> <div style="background: lime"> <div style="float: left; height: 50px; width: 100px; background:blue"></div> <div style="clear: left; margin-top: 100px"></div> </div> <div style="background: yellow">next</div> This time, the clearing element has a /top/ margin of 100px. Let's assume the pre-2007 definition of top border position of self-collapsing elements. With clear:none, the float's parent P is self-collapsing, so by 8.3.1.6.2, P's top border position is flush with the bottom of "before". The clearing element C is also self-collapsing, and so by 8.3.1.6.1, C's top border position is the same as P's. C's top border position is not past the float and so we introduce clearance. C no longer collapses its top margin with P's top margin. We recompute the layout, and P's top border position (and hence the float) stays flush with the bottom of "before". For C's current position, 8.3.1.6.2 applies and we find that it is 100px below the bottom of "before". Clearance is -50px, and C – and hence "next" – moves upwards... meaning that C's top margin is effectively ignored. So you lose either way; the existence of the problem is *not* dependent on the choice of temporary border edge used in 8.3.1.6.2 to determine top border position. Secondly, it's not the use of 8.3.1.6.2 /per se/ that causes our problem; rather, it's the use of that rule when the self-collapsing element has clearance. Let's look again at the first example. With clear:none, P's (and hence C's) position was "low", relative to the 100px collapsed margin to which C's margins contribute. Inhibition of margin collapsing forces P and the float upwards, and also means that C's top border position is calculated differently: suddenly it's "high" (in fact, incident with P's), relative to the 100px collapsed margin. Now, proceeding to use clearance to push C back downwards isn't what we're complaining about, assuming that we accept the desirability of Calculation 2 in the first place, since we have no basis on which to distinguish self-collapsing elements from others in this regard. What's problematic is that C's bottom margin is now in some sense "below" C's position, pushing subsequent elements even further downwards when clearance moves C downwards, whereas initially it was "above" it when clear:none was assumed. We can solve this with the following modification of 9.5.2, which bypasses 8.3.1.6.2 once clearance is introduced, for the situation that causes us difficulty: # If this hypothetical position of the element's top border edge is # not past the relevant floats, then clearance <del>must be</del> # <ins>is introduced and margins collapsed anew according to the rules # in 8.3.1. However, if the element's top and bottom margins # collapse, and the resulting margin collapsed with the parent's top # margin when the hypothetical position was calculated, then the # element's top border position is taken to be the same as that of a # hypothetical immediately-following sibling with zero top margin and # non-zero top border rather than that specified in 8.3.1. # # Then the amount of clearance is</ins> set to the greater of: This introduces a change only in the narrow case we're interested in. What we're doing is engineering the situation to ensure that the element's bottom margin doesn't influence the size of the collapsed margin below the redefined top border edge position. This definition change doesn't matter to the clearing element itself, since the whole point of clearance is to shift the rendering so that the clearing element ends up where we want it; the mechanics of how the end result is achieved is unnoticeable. It remains to verify that it doesn't harm any otherwise-good test cases by influencing the position of surrounding elements, as follows. It doesn't affect the clearing element's children, since these are necessarily self-collapsing and so their position remains the same as that of the element itself (by 8.3.1.6.1), whatever that is defined to be. (Note that this is unlike the situation arising from some unnatural notion of hypothetical top border edge being used in 9.5.2, in which a child's hypothetical position could end up higher than its parent's actual position, causing pathological cases when both parent and child have clear set. That is another reason to discount any notion of hypothetical top border edge other than the "real" one I've been advocating throughout this thread.) It doesn't affect the clearing element's previous siblings since they share the parent's position – a relationship that is unaffected by the introduction of clearance, and a post-clearance position that is unaffected by how the position of the clearing element is defined (and which is necessarily not below the bottom of the relevant floats, and hence is above the post-clearance position of the clearing element). It doesn't affect the clearing element's subsequent siblings, in the sense that these remain in positions at least as low as the clearing element's position (due to 8.3.1.6.2's bottom border device). I believe that this addition to my original proposal excludes all undesirable renderings, and hence fulfills the WG's original goal. Moreover, it is the only proposal known to do so. [1] http://lists.w3.org/Archives/Public/www-style/2010Jul/0035.html Cheers, Anton Prowse http://dev.moonhenge.net
Received on Wednesday, 25 August 2010 23:20:37 UTC