Updated (2009-01-15): I finally stumbled across the answer (see below).
[Originally posted 2008-01-18] I’ve recently come to understand a bug in how Internet Explorer handles floats. I doubt this is a new discovery, but I haven’t read about it and can’t easily find it through Google. To put it simply, floated boxes should overlap non-positioned block boxes but displace inline boxes; Internet Explorer displaces both. Now that I’ve said it simply, I’ll try to say it more clearly and accurately and with pictures.
We’ll start with a pretty simple XHTML document:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<title>IE Float Bug</title>
</head>
<body>
<p id="red">red</p>
<p id="blue">blue</p>
</body>
</html>
Now let’s add some color and play with our p
boxes, adding the following to our header:
<style type="text/css">
p {
margin: 0 5px 0 0;
padding: 0;
color: #FFFFFF;
border: 5px solid #000000;
text-align: center;
}
#red {
background-color: #FF0000;
width: 100px;
height: 100px;
line-height: 100px;
}
#blue {
background-color: #0000FF;
width: 150px;
height: 150px;
line-height: 150px;
}
</style>
That should give us a page that looks like:

Now, let’s add float: left;
to #red
and see what happens in Firefox:

To explain what’s going on here, #red
is removed from the normal flow of the document. #blue
, then, being a block box, moves to where it would be if #red
were not in the document at all. The text inside of #blue
, though, has to be aware (if you’ll allow this personification) of the float, because its line box has to be shortened to avoid overlapping with #red
‘s margin box. This all conforms to the CSS 2.1 visual formatting model.
But look at what happens in Internet Explorer 7:

Instead of just displacing the text, the entire block-level box #blue
has shifted to make room for #red
. This would be entirely appropriate if I had created a new block formatting context by, for example, adding overflow: hidden
to #blue
. But so long as #blue
‘s overflow
is set to its default value of visible
, as it is here, we have no new block formatting context, so #red
should overlap #blue
.
So how do I fix this? How do I make IE render this the same way as Firefox? I would appreciate any help.
Update: The Answer
If you can avoid triggering hasLayout in IE, then #blue
will behave as it should. In the example above, setting height
and width
on #blue
both triggered it, but with a few changes, we can avoid that to get the results we want.
First, remove height
and width
from #blue
. To be honest, height
wasn’t necessary, since line-height already sets the height of the element (assuming you’ve only one line of text).
So how do we constrain the width? By setting width
on body
(or a div
that wraps both p
s, if you want to do this in the context of a real page). So give body
a width
of 165px
(to accommodate the desired width, margin, and border or #blue
).
So our final CSS looks like:
<style type="text/css">
body {
width: 165px;
}
p {
margin: 0 5px 0 0;
padding: 0;
color: #FFFFFF;
border: 5px solid #000000;
text-align: center;
}
#red {
background-color: #FF0000;
width: 100px;
height: 100px;
line-height: 100px;
}
#blue {
background-color: #0000FF;
line-height: 150px;
}
</style>
That gives us the same result in IE and Firefox.