Containing Float Elements

Developers who are new to css, or those who work primarily in IE, run into a vicious “bug” in Firefox and other modern browsers. Their backgrounds disappear, or their borders do—but everything's fine in IE. The gnashing of teeth is heard throughout the land.

The truth is, there's a reason for the behavior, and IE has screwed up again. The culprit is a wad bug known as hasLayout. I won't discuss it except in passing. The best public documentation has been written by Ingo Chao et al in On having layout I strongly recommend you study the article thoroughly.

In this demo, there are two ways to see what's going on, IE's way, and the right way. For best results, you'll need to compare one to the other. Open the page in both IE and a modern browser, i.e. Firefox, Opera or Konqueror/Safari.

IE7 has internalized many of the IE6 bug work-arounds. IE8 has killed off hasLayout, and expanded css2.1 support.

Basic Non-Enclosed Float

Notice that in the first box, the float element extends beyond the parent div. This is correct behavior. In the second box, the parent is given a width. This sets the proprietary IE property, hasLayout, to true. When true, IE wrongly encloses the float.

On a side note, IE does not properly handle collapsed margins when an element has layout. Margins should not collapse when the element has padding or borders, or if it is a float element. In IE-speak, a float always has layout. You can see that the float margin collapses in both cases and the non-float margin collapses in the sized parent but not the unsized.

Now is the time for all good men to come to the aid of their country.

This is non-float content.

Now is the time for all good men to come to the aid of their country.

This parent has {width: 500px;}.

Using The Overflow Property

If the parent element has an overflow: value other than the default “visible”, the height of the element will be sufficient to contain child floats.

Notice that IE≤6 fails to follow the rules. IE will work if the parent is given a width. That is due to a dimensioned element in IE expanding to enclose its content. IE7 has added {overflow: hidden || auto;} to the list of properties that trigger hasLayout.

Now is the time for all good men to come to the aid of their country.

This parent has {overflow: hidden;}.

Now is the time for all good men to come to the aid of their country.

This parent has {overflow: auto;}.

Now is the time for all good men to come to the aid of their country.

This parent has {width: 500px;} along with {overflow: hidden;}.

Using The Display Property

Tables and table cells automagically enclose their content. Even if a height is declared, it is treated as a minimum. We can declare that an element is {display: table;} or {display: table-cell;}. Notice, too, that tables and table cells will shrink wrap the content. Since this is one more example of IE not following the specs, it's a good idea to specify a width so both IE and modern browsers will render the same.

The table-cell value is troublesome because it is an inline rendering which wouldn't be easily adapted to IE.

Notice that there is no margin on the cells (in modern browsers, margin is not a property of td (the html equiv.). You would use {border-spacing: length [length];}.

(Adds the inline-block display property to the demos.)

The inline-block display value works about the same in modern browser as in IE<8. In older IEs, hasLayout is triggered, and in modern browsers, a new block formatting context is established.

IE<8 does not support inline-block on other than inline elements, so the value sets hasLayout and must then must be reset to either block or inline. Firefox 2 uses the proprietary experimental value of -moz-inline-box.

Now is the time for all good men to come to the aid of their country.

This is {display: table;}.

Now is the time for all good men to come to the aid of their country.

This is {display: table;} and {width: 500px;}.

Now is the time for all good men to come to the aid of their country.

This is {display: inline-table;}.

Now is the time for all good men to come to the aid of their country.

This is {display: inline-table; width: 300px;}. Width is for IE<8.

Now is the time for all good men to come to the aid of their country.

This is {display: table-cell;}.

Now is the time for all good men to come to the aid of their country.

And so is this.

Now is the time for all good men to come to the aid of their country.

This is {display: inline-block;}.

Using a Float Parent

A float element will contain its child floats. A float without dimension will shrink-wrap its content. If you don't want following elements to wrap the parent, they will need to be cleared.

Now is the time for all good men to come to the aid of their country.

This is a float parent

Now is the time for all good men to come to the aid of their country.

This is a sized float parent

This following element will need to be cleared if you want it to appear below the container.

You will see yet another IE6 bug here. The left margin of the far left parent float is doubled. You may fix it by giving the container {display: inline;}. All browsers ignore the inline, as they should, but in IE it fixes the bug—there's no rhyme or reason, it's IE.

Using Tony Aslett's Clearfix Hack

This is a very elegant approach to clearing floats. It uses the :after pseudo element to add a clear: just prior to closing the parent element. This forces the parent to enclose its float(s). See Big John's explanation, or go to Tony's description.

Notice that IE wrongly collapses both the float and the parent margins. This is because the parent, in IE, is given hasLayout so it will enclose the float.

Now is the time for all good men to come to the aid of their country.

This uses Tony's hack.

What's It All About?

You say, IE doesn't need all this, why all the fuss? That's true. As long as your float's parent has a dimension, it will automagically enclose all its content. That sounds good until you have a dimensioned box and you want the content to hang out. There is no way to do that. Let me repeat, there is no way to do that—none. Doesn't seem like such a good idea any more, now does it?

None of these methods can be used in every situation, but for any given case, at least one will be useful. So give it some practice and learn the limitations of each. You'll be glad you did.