Ian Clark
Ian Clark

Reputation: 9347

The impact of 'overflow' values other than 'visible' on the block formatting context

This question is similar to this one (with an excellent answer), although mine doesn't pertain to float issues.

I recently ran into some trouble when trying to apply a margin to an only-child of a block-level element:

#parent {
    background: rgba(255, 0, 0, 0.1);
}

#child {
    margin: 30px 0;
    padding: 20px;
    background: rgba(0, 255, 0, 0.1);
}
<div id="parent">
    <div id="child">Foo</div>
</div>

Although the margin is applied, the parent's background is not. This remains true unless siblings are added before and after the #child, or (more interestingly in my opinion), an overflow of any value other than visible is set. Here is the same example but with an overflow value:

#parent {
    background: rgba(255, 0, 0, 0.1);
    overflow: auto;
}

#child {
    margin: 30px 0;
    padding: 20px;
    background: rgba(0, 255, 0, 0.1);
}
<div id="parent">
    <div id="child">Foo</div>
</div>

From CSS2.1 Section 9.4.1 - Block Formatting Contexts, I found the following:

Floats, absolutely positioned elements, block containers (such as inline-blocks, table-cells, and table-captions) that are not block boxes, and block boxes with 'overflow' other than 'visible' (except when that value has been propagated to the viewport) establish new block formatting contexts for their contents.

I'm really struggling to understand the rationale behind the "overflow other than visible" logic in this instance. The margins are seemingly not being clipped in this situation, as the only thing to change is the background. Could someone demonstrate why a value of overflow: visible creates such a situation?

Upvotes: 8

Views: 365

Answers (3)

Salman Arshad
Salman Arshad

Reputation: 272136

In your first examples the top and bottom margins of parent and child are collapsed. Roughly speaking, the 30px margin of child is combined with the zero margin of parent, the greater margin of the two is applied on the parent. Quote:

In CSS, the adjoining margins of two or more boxes (which might or might not be siblings) can combine to form a single margin. Margins that combine this way are said to collapse, and the resulting combined margin is called a collapsed margin.

In the same document, the effect of overflow (as in your second example) is explained:

Margins of elements that establish new block formatting contexts (such as floats and elements with 'overflow' other than 'visible') do not collapse with their in-flow children.

Upvotes: 1

BoltClock
BoltClock

Reputation: 723729

As I have covered in my answer to the question that you link to, the main reason overflow values other than visible result in a new block formatting context is due to implementation limitations relating to floats, even though the concept of overflow does not immediately appear to have a relationship with floats.

While the relationship between floats and collapsing margins is pretty simple (it never occurs), the fact that margins cannot collapse through the boundaries of an element with such a value for overflow either is little more than a side effect of this change, because margins are defined not to collapse through any box that establishes a block formatting context, as described in section 8.3.1. I quote:

  • Margins of elements that establish new block formatting contexts (such as floats and elements with 'overflow' other than 'visible') do not collapse with their in-flow children.

This includes both floats and elements with such a value for overflow. The overflow itself does not actually have any direct effect on the margins.

When both the parent and the child are block-level elements that participate in the same block formatting context, they will collapse by default unless there is something in the way:

  • The top margin of an in-flow block element collapses with its first in-flow block-level child's top margin if the element has no top border, no top padding, and the child has no clearance.

  • The bottom margin of an in-flow block box with a 'height' of 'auto' and a 'min-height' of zero collapses with its last in-flow block-level child's bottom margin if the box has no bottom padding and no bottom border and the child's bottom margin does not collapse with a top margin that has clearance.

This explains why the parent's background does not extend until you try and block the margin collapse.

Upvotes: 2

Jen
Jen

Reputation: 1733

This clarifies an issue I've occasionally had with heights. It looks like the height of the parent element is not being calculated from the margins of the child.

Adjusting your fiddle: http://jsfiddle.net/u6tQj/2/

#parent { background: #555;}
#child { margin:200px; background: #ccc; }

The margins are being applied to the child, but the height of the parent was unaffected. Adding overflow or border causes the height to adjust. I do sometimes struggle with why parent elements don't always expand to contain the children.

It seems very odd, but...

It could be complicated to have conflicting rules on parent height. It would affect many of the browser layouts, such as parent position relative with children set to absolute, or overflow auto/hidden, and probably a host of other layout algorithms. I imagine it would unnecessarily complicate the browser's layout engine, in the same way that css selector specificity can sometimes be a major pain for us.

You would add padding to the parent to adjust its height, which is more intuitive (isn't it?).

Upvotes: 0

Related Questions