Floating Elements Are Outside of Containing Blocks

What's the containing block of floated elements?

The premise of your question is flawed. An absolutely positioned element cannot float, and a float cannot be absolutely positioned. From section 9.7:

[...] if 'position' has the value 'absolute' or 'fixed', the box is absolutely positioned, the computed value of 'float' is 'none' [...]

So you're not trying to find the containing block of a float here. You're trying to find the containing block of an absposed element.

Having said that, if you really must know, the containing block of a float is the same as for relatively positioned or non-positioned elements as I described in my answer to your previous question, since floats cannot be absposed.

Floating elements within a div, floats outside of div. Why?

The easiest is to put overflow:hidden on the parent div and don't specify a height:

#parent { overflow: hidden }

Another way is to also float the parent div:

#parent { float: left; width: 100% }

Another way uses a clear element:

<div class="parent">
<img class="floated_child" src="..." />
<span class="clear"></span>
</div>

CSS

span.clear { clear: left; display: block; }

Do block elements ignore floating elements?

Several paragraphs after the one you quote, the spec says:

The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap the margin box of any floats in the same block formatting context as the element itself.

Although you've applied display: block to your image, being an image it's a replaced element, and therefore the float cannot intrude into its bounds.

Only non-replaced block boxes that don't establish block formatting contexts and are in the same flow as a float may ignore the float.1 A block-level replaced element is not a block box, because a replaced element cannot be a block container box.2


1 You're probably thinking, that's a ridiculously specific statement, and it is. It's why terms like "block element" are considered extremely vague in CSS parlance. Then again, it doesn't help that CSS itself defines almost equally vague terms like "block box" to specifically refer to boxes that are both block-level boxes and block container boxes.

2 This does imply that "non-replaced block box" is somewhat of a tautology, which reinforces just how ridiculously specific that statement is.

Why do floated elements not overlap a block-element if they are defined after them in the HTML structure?

Thinking about the vertical progress of the Document Flow will answer your question.

In your second example, although unstated in the CSS, .center has the default positioning and the default display for a <div>:

.center {
position: static; // by default
display: block; // by default
background-color: lightcoral;
}

That means it completes displaying itself within the vertical flow, as a statically positioned, block-level entity.

Then, after this element completes displaying itself (within the flow), the next element in the vertical flow is .left-box.

.left-box begins displaying itself at the first available point within the vertical document-flow.

But the top of .left-box can't be any higher than the bottom of .center because the latter has already completed positioning and displaying itself within the vertical document flow.


In your first example, .center also begins at the first available point within the vertical document-flow... but, by contrast, this first available point is no lower than where .left-box begins.

Why not? Because, as a floated element, .left-box is absent from the vertical document-flow.

This means that .center may essentially ignore .left-box and display itself within the vertical document-flow precisely where it would have displayed anyway if .left-box didn't exist.

Spacing out floating elements with both sides of a container

Here is one way of realizing your layout using inline-blocks instead of floated elements.

First, to the .blue containing block, set the following CSS properties: text-align: justify and line-height: 0.

Second, for the .red child elements, remove the float property and add display: inline-block.

The result is that your .red elements are now inline and will be spaced evenly in a line within the width of the .blue container. Since you hard-coded a nice value of the width for .blue, you will get the horizontal spacing that you want between the .red blocks (no need to set a right margin).

The remaining issue with text-align: justify is that the final line will not stretch to fill the full width (this is how the justify setting works in order to prevent short lines from being stretched out in a ugly fashion).

To work around this, add a pseudo-element .blue:after which is an inline-block of width 100%. This will force a new line to be created after your red blocks, and the result is that all the red blocks are left/right justified.

The line-height: 0 on .blue and vertical-align: top on .blue:after take care of any extra white space at the bottom due to line leading (space above and below the baseline of the text).

.blue {

margin-top: 10px;

background-color: #00A2E8;

height: auto;

overflow: auto;

padding-bottom: 10px;

text-align: justify;

line-height: 0;

}

.blue:after {

content:'';

display: inline-block;

width: 100%;

vertical-align: top;

}

.red {

background-color: red;

width: 50px;

height: 50px;

display: inline-block;

margin-top: 10px;

}
<div class='blue' style='width: 110px'>

<div class='red'></div>

<div class='red'></div>

</div>

<div class='blue' style='width: 110px'>

<div class='red'></div>

<div class='red'></div>

<div class='red'></div>

<div class='red'></div>

</div>

<div class='blue' style='width: 170px'>

<div class='red'></div>

<div class='red'></div>

<div class='red'></div>

<div class='red'></div>

<div class='red'></div>

<div class='red'></div>

</div>


Related Topics



Leave a reply



Submit