- From: Anton Prowse <prowse@moonhenge.net>
- Date: Mon, 05 Jul 2010 00:19:04 +0200
- To: www-style list <www-style@w3.org>
- CC: Bruno Fassino <fassino@gmail.com>, "Tab Atkins Jr." <jackalmage@gmail.com>
This post is mainly just a pigeon-hole for my analysis of one of Bruno's test cases. But it does lead me to the following conclusions, of wider interest: (i) The change in 2007 from using top border to bottom border in 8.3.1-6.2 has indeed had subtle effects that were not immediately obvious, just as Hixie feared.[1] (However, the above change also brought benefits, and it's not desirable or at all realistic to roll it back.) (ii) It's possible to mitigate the problem demonstrated in the test case by changing how the hypothetical top border position of a self-adjoining clearing element C is calculated when determining if clearance is needed, just as Tab and Bruno have been discussing in this thread. (iii) I buy Bruno's arguments in [3] and [4] (later in the thread than this post that I'm replying to) that it's reasonable to calculate the hypothetical position under the condition that C is prevented from collapsing its bottom margin with its top margin via the temporary assumption of a non-zero bottom border. (iv) I also buy Tab's argument in [5] that such a change might be nice to have, but another, simpler solution is to just ignore the problems that self-adjoining clearing elements cause, by way of calculating the hypothetical top border position under the sole assumption that C has clear:none (so that all margins collapse normally during this calculation). This is a very thorny topic, and its possibly reassuring that several of us are iterating to the same conclusions -- although we are doing so on the basis of the same test cases. Now, any change to the current spec is bound to create the occasional strange special cases, but given that no-one seems too clear what the current spec is trying to say anyway with its "preceding margins", proposing a change doesn't seem unreasonable. By adopting Bruno's proposal, it appears that we're pushing the strange cases largely out of sight. It goes without saying, however, that existing known corner-cases such as Hixie's and David Baron's test cases should be carefully checked to ensure that neither of the proposed changes alters the expected behaviour. ===== Bruno Fassino wrote: > On Mon, Jun 28, 2010 at 8:43 PM, Tab Atkins Jr. <jackalmage@gmail.com> wrote: >> On Mon, Jun 28, 2010 at 11:01 AM, Bruno Fassino <fassino@gmail.com> wrote: >>> On Mon, Jun 28, 2010 at 6:50 PM, Tab Atkins Jr. <jackalmage@gmail.com> wrote: >>>> I added language to make it clear I'm explicitly defering to the >>>> normal margin-collapse rules. This isn't meant to be a special case; >>>> it should lay out the element *exactly* like it wasn't clearing at >>>> all. >>>> >>>> Is that sufficient? >>> >>> It is not explicitly stated what margins are considered during this >>> collapsing to determine the hypothetical position. >>> It is said "preceding margins", but I don't think this is precise enough. >>> >>> Consider something like this: >>> >>> <div style="background: lime; border-top: 1px solid"> >>> <div style="float: left; background: blue; height: 50px; width: 100px"></div> >>> <div style="clear: left"> >>> <div style="margin-top: 60px"></div> >>> </div> >>> </div> >>> <div style="background: yellow">next</div> >>> >>> (you can see it at http://brunildo.org/test/margin-collapse-clear-child-7.html) >>> >>> Should the top margin of the child of the div with clear, after the >>> float, be considered in the computation of the hypothetical position? >>> It collapses with the (null) top margin of the clear, but does not >>> seem to be a "preceding" margin. >>> >>> However I doubt the intention is to really exclude it. At least >>> Firefox and Safari seem to behave as if it was considered in the >>> hypothetical position, and so as if no clearance was necessary here. >> Again, the intention is to collapse all margins exactly as they would >> normally be collapsed, as if clearance wasn't present. Should I >> remove the word "preceding" or something, if that's causing the >> confusion? Perhaps this would work better: >> >> """ >> 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. This position is determined >> after the top margin of the element has been collapsed with all >> appropriate adjoining margins, per normal margin-collapsing rules. >> """ >> >> ~TJ >> > > > Yes, without the word "preceding" there is no more confusion about its meaning. > > The only problem is that I'm not sure that the intention is really to > have the hypothetical position the same as the one with _all_ margins > normally collapsed (i.e. the same as with clear: none). > In other words, I'm not sure if the word "preceding" was initially > there for any specific reason. > > Consider this: > > <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> > > (you can see it at http://brunildo.org/test/margin-collapse-clear-child-9.html) > What behavior do we want for this test case? My back-of-a-large-envelope calculations are as follows. First assume that the clearing element C was in fact clear:none. The final collapsed margin in which C's margin participates would be 100px. C's parent (the lime div) would have zero height. We'd see a yellow "before" followed by 100px of white space followed by a yellow "next". In order to know where to position the float, we need to calculate the top border position of the lime div. 8.3.1-6.2 applies, and the position of its top border edge is the same as it would have been if it had a non-zero bottom border. This bottom border would be 100px below "before", and hence so would the top border position due to the div's zero height. The top border position of the anonymous box around the float, by the rules of 8.3.1-6.1, is the same as the top border position of the lime div; thus the top of the float would also be 100px below "before", flush with the top of "next". Tab's original proposal was to calculate the hypothetical position of the top border of C under the conditions above. 8.3.1-6.1 applies, and the top border position of C would be the same as that of its parent lime div, 100px below "before" and flush with the top of the float and the top of "next". This is *bizarre*, and we shall come back to this point later. Since this hypothetical top border position is not past the float, we introduce clearance, and should calculate its size. We're trying to "shift C up or down" as necessary so that its top border position is the lower of "flush with the bottom of the float" and "flush with its previously-determined hypothetical position"; the latter is lower. To know how much to shift, we need to know where the top border position of C currently is, taking into account that we've now introduced clearance and so C's top margin is prevented from collapsing with the top margin of its parent lime div. C's bottom margin doesn't collapse with its parent's bottom margin either, due to the rule near the bottom of 8.3.1. Hence the parent lime div is precisely 100px high, containing the uncollapsed 100px bottom margin of C, and is immediately preceded by "before" and immediately followed by "next". The position of C's top border is currently the same as it would have been if C had a non-zero bottom border (8.3.1-6.2), which is to say, at the top of the lime div, flush with the bottom of "before". So we finally know that we need "move C downwards" by 100px (ie, the clearance is 100px) -- or more accurately, put a 100px uncollapsable extra space above the combined 100px margin caused by C -- causing the parent lime div to be 200px high. > With the new formulation the top border edge of the clear should be > 100px lower than the bottom of "before" (hypothetical position), but > then (since with clear there is no more collapsing with the parent > top) we should have other 100px below this position. Or something like > that... Not quite, but the right kind of idea, as we've just seen! We've got a 200px-high lime div, which doesn't seem ideal. (No browser gets this right, as I'm sure you've already observed: Opera 10.53, Safari 4 and and IE8 think the div should be 50px high [and goodness knows where they're putting the 100px margin]; IE6 thinks the div should be 100px high, whilst IE7 thinks it should be zero height but uses a 100px space instead; Firefox 3.6 thinks the div should be 150px high.) So what's actually going on in this test case? The hypothetical position of C's top border turned out to be quite low down. This is because its parent's temporary bottom border is used to determine its top border position which in turn is used to determine C's hypothetical top border position -- at the /bottom/ of the 100px combined margin generated by C's bottom margin! Once clearance was introduced, the float moved up, as did C's top border position -- this time to the /top/ of the 100px combined margin. But C was still required to move down by 100px :-/. Surely we'd prefer it to only move down by 50px -- the height of the float. Who's to blame? Well, the use of bottom border to determine the top border of the lime div is the primary culprit. Had top border been used instead, as the spec used to require, then the top border position of the lime div would have been directly below "before", as would the top of the float and the hypothetical position of C's top border. Clearance would be introduced, which wouldn't affect the top border position of the lime div, the float would stay where it was, the clearance would be 50px and C would "move down" to just below the float, as we might have liked. If nothing else, the latter result vindicates Hixie who expressed strong reservations about changing from top border to bottom border in 8.3.1-6.2, stating that:[1] "If we change these rules it could have very subtle effects that might not be understood for years, at which point we'd be back to the same position as we are in now: thinking the rules are unintuitive and wanting to change them in another subtle way." Now, that change meant that other test cases became more intuitive, which was Alex Mogilevsky's motivation for starting that thread back in 2007 (and David Baron also produced the strong argument in [2] that it gets along better with incremental rendering -- although I'm still in the process of trying to understand the reasoning for that, since my end-of-day brain seems to think exactly the opposite should be true). So there's no reason to suggest that the change be rolled back, and there's no way anyone would accept that anyway. So what to do? Probably, mitigate the problem by changing how the hypothetical top border position of C is calculated when determining if clearance is needed. We should "push it downwards" somehow when C's bottom margin is involved. This is exactly what Tab and Bruno were discussing in the quoted section above. What's more, I buy Bruno's arguments in [3] and [4] (later in the thread than this post that I'm replying to) that the hypothetical position should be calculated under the condition that C is prevented from collapsing its bottom margin with its top margin via the temporary assumption of a non-zero bottom border. [1] http://lists.w3.org/Archives/Public/www-style/2007Sep/0046.html [2] http://lists.w3.org/Archives/Public/www-style/2007Sep/0100.html [3] http://lists.w3.org/Archives/Public/www-style/2010Jun/0643.html [4] http://lists.w3.org/Archives/Public/www-style/2010Jun/0664.html [5] http://lists.w3.org/Archives/Public/www-style/2010Jun/0651.html Cheers, Anton Prowse http://dev.moonhenge.net
Received on Sunday, 4 July 2010 22:20:20 UTC