Skip to main content

Float containment

Published on , updated on

This article gives a brief overview of float containment. There are a great many articles on this subject out there already, of course, but I feel that most of them are outdated or confusing. If you just want the quick & dirty, head over to the summary.

The problem

A floated element overlapping the borders of other elements

Figure 1. A float overlapping the border of its containing block-level element, and the one below it.

I'll keep this short, as you're probably already aware of the issue if you're reading this :-). Figure 1, taken from the section on floats of the official CSS 2.1 Specification, shows a graphic of the problem. Actually, the displayed behaviour, in itself, is not a problem: it is in fact a very useful feature of floats. However, it can become a problem when the goal is not to have content flow around your floated element(s), but to line up several block boxes horizontally. Often, you'll want the containing element to “be aware” [1] of its floated children for styling purposes — but this is simply not the default behaviour of floats, as they are taken out of the normal document flow. The containing element does not expand to fit its floated children. We can easily remedy this, however...

What not to do

Probably the most common solution found on the web is to place an additional element in the HTML source (often a BR or DIV), after the float(s), styled with clear: both — or even worse, a BR element with <br clear="all">, a long-forgotten (or so you would hope, anyway) HTML 3.2 attribute. This goes against the principle of separating content and presentation and can cause issues when designing alternate styles that require this behaviour to be absent. Remember folks: every time you use this method, God kills a kitten... or something.

Luckily, we can easily do it all through CSS, as we'll see next.

Solution for modern browsers

Modern browsers, including IE8, can be made to contain floats purely with CSS in two ways. The first one is to simply give the containing element overflow: hidden (or any value that isn't the default of visible) [2]. Incidentally, this method works in IE7 too. However, sometimes you cannot use this approach as you may be displaying content outside of the containing element on purpose — such as in the case of drop down menus or other visual effects.

There is another method that does not suffer from this “restriction”, though. Making use of CSS Generated content, we can inject a pseudo-element into the page, after the float(s), and use that pseudo-element to do the clearing for us. Assuming #foo is the containing element...

#foo:before,
#foo:after {
  content: '';
  display: table;
}

#foo:after {
  clear: both;
}

Solution for legacy versions of Internet Explorer

Dealing with Internet Explorer 6 and 7 is a breeze, too. In these browsers, the retarded hasLayout property is responsible for float containment.

If you're using the overflow method for modern browsers, then you'll find this works in IE7 as well, as any value for overflow other than the default of visible happens to give layout in this version. In IE6, however, this is not the case. Below, you will find my preferred method of giving layout in IE6 — but please refer to the hasLayout article I just linked to for other methods. Again, the following code assumes that #foo is the containing element.

#foo { display : inline-block; }
#foo { display: block; }

The advantage of the above code, is that you can keep it in your regular style sheet without it being invalid (as opposed to using zoom: 1) and it has no negative side effects in any browser. Please remember that you have to have the rules in two separate declaration blocks and in the same order, as shown — although you may place additional rules in either block, if you so wish.

Summary

Cross-browser float containment can be achieved by applying overflow: hidden (for modern browsers) and hasLayout (for legacy versions of Internet Explorer) to the containing element of the float(s). The following code shows the easiest-to-use setup, in my opinion. #foo represents the containing element.

#foo {
  overflow: hidden; /* For modern browsers and IE7 */
  display: inline-block; /* For IE6 */
}

#foo { display: block; } /* For IE6 */

If you cannot use overflow: hidden due to the fact that you need to have overflowing content, the following code is recommended:

#foo:before, /* For modern browsers */
#foo:after {
  content: '';
  display: table;
}

#foo:after {
  clear: both;
}

#foo { display: inline-block; } /* For IE6/7 */
#foo { display: block; } /* For IE6/7 */

And that, as they say, is that. Bookmark and Share

Footnotes

  1. Also see the section on block formatting context roots of the CSS 2.1 Specification.
  2. There are other ways to “activate” this behaviour, none of which are generally useful alternatives, because they trigger other effects that are often unwanted. There are definitely cases where one of these alternatives may prove appropriate, although even then, the generated content method is probably a better choice.

Updates

Updated the code for the generated content method of containing floats with the "micro clearfix". This clearfix also passes edge cases.
Updated footnote 1.
Cleaned up the code for the generated content method of containing floats to be less ancient: some of the rules that I had in there previously were merely there to cater to really old non-IE browsers.
Added footnote 2.

Comments

blog comments powered by Disqus