Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
341 views
in Technique[技术] by (71.8m points)

css - Why is this non-float margin collapsing with a float?

While investigating this question about clearing floats, I came across a peculiar situation with margins and clearance with a non-floating box.

According to section 8.3.1 of the spec, margin collapse should not occur when either

  • at least one of the elements generating the margins is a float, or
  • clearance is in the way.

But, consider a series of floating boxes, the last of which clears the rest:

<div class="container">
    <div></div>
    <div></div>
    <div></div>
    <div></div>
</div>
div.container > div {
    float: left;
    width: 50px;
    height: 50px;
    margin: 10px;
}

div.container > div:last-child {
    clear: left;
}

As you would expect, both the horizontal and vertical gaps between each box are 20 pixels wide. The vertical margins do not collapse.

However, when the clearing element is not floated, it jumps up by 10 pixels as though its top margin were collapsing with that of the float directly above it.

This behavior completely defies both conditions listed above:

  1. There is clearance.
  2. For clearance to occur, there must be some other float to clear in the first place. The fact that the clearing element itself is not floated shouldn't be relevant.

This behavior also seems to be consistent across all browsers, including less-than-recent versions of IE.

That said, I don't claim to know the CSS float model like the back of my hand, so... Can somebody else explain why this happens?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Never mind, I think I found it myself. Looks like the following assumption in my question was wrong (told you I don't fully grok the CSS float model):

The fact that the clearing element itself is not floated shouldn't be relevant.

In section 9.5.2, which describes the clear property, it says:

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. This position is where the actual top border edge would have been if the element's 'clear' property had been 'none'.

If this hypothetical position of the element's top border edge is not past the relevant floats, then clearance is introduced, and margins collapse according to the rules in 8.3.1.

Then the amount of clearance is 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 place the top border edge of the block at its hypothetical position.

And further down that section, it says:

When the property is set on floating elements, it results in a modification of the rules for positioning the float. An extra constraint (#10) is added:

  • The top outer edge of the float must be below the bottom outer edge of all earlier left-floating boxes (in the case of 'clear: left'), or all earlier right-floating boxes (in the case of 'clear: right'), or both ('clear: both').

(Emphasis mine. Note that "outer edge" is synonymous with "margin edge", as described in section 8.1.)

Essentially, this means if the clearing element is not floated and its top margin alone does not push it far enough away from the floats, then the element is pushed just enough for its top border to sit right underneath the bottom margin of the float being cleared. While it would appear as if its top margin was collapsing with the bottom margin of the float, in reality the top margin doesn't have any meaningful effect because it doesn't reach the border edge of the clearing element.

Otherwise if the clearing element is floated, then its top margin is taken into account, so to speak (as consistent with the rules stated in 8.3.1).

And as I write this, I recall that in-flow non-floating elements are positioned as if the floats were never there to begin with, because floats are taken out of the normal flow. In other words, any top margin that is set on a non-floating clearing element does not take into account any floats, regardless of whether it is enough for clearance. For example, when both clear and float are set to none on the last element, it sits flush with the edges of its container in the exact same position as the first floating element, albeit behind it (note that the borders on the container block margin collapse between it and the container).

Lastly, the fact that clearance is introduced is actually not relevant in this specific situation, because clearance blocks margin collapse only when the element's margins would normally have collapsed had its clear property been set to none. Since we're talking about floats here, margin collapse should indeed never happen normally, and so whether or not the last element has clearance isn't relevant (not directly, anyway).


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...