Why clearance sometimes needs to be negative (18:04 -0700)
At the CSS working group meeting in Oslo in August 2003, we came up with a concept called clearance to describe the offset used to change the position of a non-floating element that is moved by the clear CSS property. (Previously, the clear property was defined as increasing the margin.)
At our meeting earlier this week in Mountain View, we discussed a testcase where the current rules cause very strange behavior. The simplest form of this testcase is the following (view):
<div>A</div> <div> <div style="float:left;height:10px;width:10px;background:blue"></div> <div style="clear:left; margin-top: 50px">hello</div> </div>
In an implementation conformant to the current CSS2.1 spec, the 50px top margin of the second inner div disappears, which doesn't seem to be desirable behavior. We're still discussing how to fix this.
But one thing that came up during the discussion is why clearance ever needs to be negative (as it is in this case). A simple example of why clearance needs to be negative is the following testcase:
<p style="height: 20px; margin-bottom: 20px;"> <img style="float: left"> </p> <p style="margin-top: 20px; clear: left">Hello</p>
In this testcase, if the image is 40px tall (view), there is no clearance needed, so the paragraphs are separated by 20px (the collapsed margin). However, if the image is 41px tall (view), the second paragraph needs to clear the image, so we have clearance. Since this clearance separates the two margins, they suddenly don't collapse. So the separation between the two blocks ends up, in the current spec, as 20px margin + -19px clearance + 20px margin == 21px. If we didn't allow negative clearance it would suddenly jump to 40px, which is bad.
Now, you might wonder why we put the clearance before the margin rather than putting it between the margin and the border (which might make sense, since we're clearing the border edge). We can explain that with this testcase:
<!-- maybe something above to clear --> <div style="clear: left; background: yellow"> <h2 style="margin-top: 1em">Heading</h2> </div>
If we had put the clearance between the margin and the padding, then if there were no float to clear (view), the h2's margin would collapse with the div's and end up outside the div. But if there were a float to clear past (view), putting the clearance between the margin and border would stop margin collapsing between the h2's top margin and the div's top margin, which would mean that the h2's top margin would suddenly switch to being inside the div.
(For what it's worth, I was never all that happy with the concept of clearance in the first place. It doesn't even fix all the cases where a collapsed margin appears partly on one side of a block's border edge and partly on the other -- although it does reduce such cases to being only for empty blocks. But we then have to add some complicated workarounds to the spec to ensure that empty boxes don't end up outside their parent by providing special rules for their position at the beginning of a block, but we still allow them to be outside their parent (even without negative margins) when they're at the end of a block.)