Why does overflow: hidden have the unexpected side-effect of growing in height to contain floated elements?
This question is best explained by this fiddle, with the following HTML:
<div class="outer">
<div class="inner-left"></div>
<div class="inner-right"></div>
</div>
CSS:
.outer {
width: 100px;
border: solid 5px #000;
}
.inner-left {
float: left;
height: 200px;
width: 50px;
background: #f00;
}
.inner-right {
float: right;
height: 200px;
width: 50px;
background: #0f0;
}
Basically, I'm wondering why does overflow: hidden
cause the outer element to grow in height, encompassing the two floated elements?
To put it most simply, it is because a block box with an overflow
that isn't visible
(the default) creates a new block formatting context.
Boxes that create new block formatting contexts are defined to stretch to contain their floats by height if they themselves do not have a specified height, defaulting to auto
(the spec calls these boxes block formatting context roots):
10.6.7 'Auto' heights for block formatting context roots
In certain cases (see, e.g., sections 10.6.4 and 10.6.6 above), the height of an element that establishes a block formatting context is computed as follows:
[...]
In addition, if the element has any floating descendants whose bottom margin edge is below the element's bottom content edge, then the height is increased to include those edges. Only floats that participate in this block formatting context are taken into account, e.g., floats inside absolutely positioned descendants or other floats are not.
This was not the case in the original CSS2 spec, but was introduced as a change in CSS2.1 in response to a different (and much more pressing) issue. This answer offers an explanation for the changes. For this reason, it seems quite apt to call it a side effect, although the changes were very much intentional.
Also note that this is not the same thing as clearing floats (clearance). Clearance of floats only happens when you use the clear
property and there are preceding floats to be cleared:
-
If you have an element with
clear: both
that's a sibling of the outer element in your example, the floats will be cleared but the outer element will not stretch. -
If you have a similar element (or pseudo-element) as the last child of the outer element instead (making it a following sibling of the floats), the outer element will stretch downward in order to contain the bottom edge of that element, and for a zero-height element that essentially means the bottommost edge of the floats. This technique is known as "clearfix" because the element (or pseudo-element) has no other purpose than to force the outer element to contain the floats by way of clearance within it.
The way i explain it to my students is:
You trigger the element containing the floats by telling him, "everything that is to much, don't show", so the element will look for any content that is too much, and he will find some elements that are floating, now he knows that he should contain them.