JavaEar 专注于收集分享传播有价值的技术资料

Why do some floated elements decide to clear both?

First off, this example will only work in a browser that supports :nth-child, like Chrome or FireFox. I have an unordered list where the odd numbered list items are floated left and clear left, and the even numbered list items float right and clear right. Like so:

HTML:

<ul class="waterfall">
    <li style="height: 100px;">1</li>
    <li style="height: 200px;">2</li>
    <li style="height: 50px;">3</li>
    <li style="height: 100px;">4</li>
    <li style="height: 200px;">5</li>
    <li style="height: 50px;">6</li>
    <li style="height: 50px;">7</li>
    <li style="height: 50px;">8</li>
</ul>​

CSS:

.waterfall {width:302px;}

.waterfall LI {
    min-width: 150px;
    background-color: #CCC;
    margin-top: 2px;
}
.waterfall LI:nth-child(odd) {
    float: left;
    clear: left;
    text-align: right;
}
.waterfall LI:nth-child(even) {
    float: right;
    clear: right;
    text-align: left;
}​

Here's the fiddle.

Goal:

All odd numbered list items should be floated to the left and be stacked on top of one another with no gap in between except the 2px margin. The same is true with the even numbered list items, except they should be floated right.

Questions a nutshell:

I'm confused as to exactly why, in this example, LI #5 can't appear above LI #4 and LI #8 can't appear above LI #7. In other words, why is LI #5 clearing LI #2, and LI #8 clearing LI #5? Also, why doesn't LI #3 clear LI #2 (I don't want it to, but if LI #5 is clearing LI #2, why doesn't LI #3 join the party)?

TL;DR

My thoughts so far are somewhat inconclusive. It appears that the browser doesn't want the top of an element to appear above the top of another element if the first element is defined later in the markup. Is that true?

I understand that floated elements are placed on a line, and that any floated elements not fitting on that line will just jump down to a new line and flow from there (as opposed to the free-flow concept of absolutely positioned elements). In other words, a floated element is removed from the document flow, but not quite as literally as an absolutely positioned element, because the floated element is still positioned relative to whatever line it started from and it still takes up space in the document flow. So, how is the next "line" from which floated elements hang from determined? In this example, why isn't LI #3 clearing LI #2, but LI #5 is?

What I'm NOT looking for:

A clever solution to make this layout work by changing the markup, abandoning floats, or using JavaScript. I know how to do all that. I simply wish to be schooled in the mysterious ways of the float.

3个回答

    最佳答案
  1. It's not as mysterious as you think, and your diagram in jsFiddle actually illustrates it pretty well. Explaining it in words might be difficult but I'll give it a try:

    Essentially, 1 floats left, 2 floats right, and then 3 floats left and moves up under 2 because there is no rule that it has to clear right.

    When it comes to 4, which floats right, there is a rule and therefore you see a hard break were 4 moves under 2. This starts the cycle over as 5 now takes its position next to 4 and once again there is nothing stopping 6 from joining 4 because it doesn't have to clear left.

    7 has to be under 5 for the same reason that 4 had to be under 3 and off you go again. As mentioned in the comments, floating elements does not remove them from the flow, which is partly why you could float an img in a p and not end up with your photo way up at the top of the page, and this concept might also really help you understand exactly what's going.

    Does that help at all or just make things more confusing?

  2. 参考答案2
  3. From the CSS 2.1 spec:

    Here are the precise rules that govern the behavior of floats:

    1 The left outer edge of a left-floating box may not be to the left of the left edge of its containing block. An analogous rule holds for right-floating elements.

    2 If the current box is left-floating, and there are any left-floating boxes generated by elements earlier in the source document, then for each such earlier box, either the left outer edge of the current box must be to the right of the right outer edge of the earlier box, or its top must be lower than the bottom of the earlier box. Analogous rules hold for right-floating boxes.

    3 The right outer edge of a left-floating box may not be to the right of the left outer edge of any right-floating box that is next to it. Analogous rules hold for right-floating elements.

    4 A floating box's outer top may not be higher than the top of its containing block. When the float occurs between two collapsing margins, the float is positioned as if it had an otherwise empty anonymous block parent taking part in the flow. The position of such a parent is defined by the rules in the section on margin collapsing.

    5 The outer top of a floating box may not be higher than the outer top of any block or floated box generated by an element earlier in the source document.

    6 The outer top of an element's floating box may not be higher than the top of any line-box containing a box generated by an element earlier in the source document.

    7 A left-floating box that has another left-floating box to its left may not have its right outer edge to the right of its containing block's right edge. (Loosely: a left float may not stick out at the right edge, unless it is already as far to the left as possible.) An analogous rule holds for right-floating elements.

    8 A floating box must be placed as high as possible.

    9 A left-floating box must be put as far to the left as possible, a right-floating box as far to the right as possible. A higher position is preferred over one that is further to the left/right.

    So

    It appears that the browser doesn't want the top of an element to appear above the top of another element if the first element is defined later in the markup. Is that true?

    Yes. It's covered by rules 5 and 6 above.

  4. 参考答案3
  5. Install masonry JS and set the columns to 1px and then the margins to 2px or 3px or however much space you want between each element. Good luck!

    http://masonry.desandro.com