CSS div's overlapping

From the spec:

Since a float is not in the flow, non-positioned block boxes created before and after the float box flow vertically as if the float didn't exist.

That means elements with display: block that are not positioned ignore the float.

However, line boxes created next to the float are shortened to make room for margin box of the float.

That means inline elements do flow around floats. That's why your <span> and the text within <p> flows around div.left, even though the <p> and div.right do not.

The border box of a table, a block-level replaced element, or an element in the normal flow that establishes a new block formatting context (such as an element with 'overflow' other than 'visible') must not overlap any floats in the same block formatting context as the element itself. If necessary, implementations should clear the said element by placing it below any preceding floats, but may place it adjacent to such floats if there is sufficient space.

And, that - obtuse as it is - is the answer to your problem. You must insert a "new block formatting context".

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

The easiest of these for you is1:

div.right { overflow: auto; }

Note that you probably also want1:

div.comment { overflow: auto; }

To fix a related, but different problem. If your <p> content is shorter than your image, then the floated div.left will not expand the height of div.comment. Adding overflow: auto; takes you into the aptly named Complicated Cases portion of the spec:

If the [Block-level, non-replaced elements in normal flow when 'overflow' does not compute to 'visible'] element has any floating descendants whose bottom margin edge is below the bottom, then the height is increased to include those edges

Which basically says that floats only expand overflow <> visible containing elements.

1 overflow: hidden; would also work, but would crop content instead of throwing scrollbars if needed.


What you're seeing is that inline elements will respect floats but block level elements do not. You have to manually space around them or floats will overlap them.

Either that or float the other block level element.