[CSS21] line boxes next to floats in different containing blocks

A few months ago, Erik J, a participant on SitePoint forums,[1] came up
with a highly ingenious way of simulating "float:center" (content
flowing either side of a horizontally-centred box) in CSS 2.1,
summarized below. Whilst the exercise was just for fun of course, his
approach reveals some interesting browser behaviour which is not clearly
specified by CSS 2.1, related to the interaction of line boxes next to
floats in different containing blocks. (Topics related to floats and
containing blocks have been troublesome in the past, too; eg [2].)

In a simplified test case[3] of his solution, which is best viewed in
Firefox 3.5 or IE8 to begin with, we have horizontally-centred
block-level container with a specified width and a large specified
height.  Its negative margin-bottom is of the same magnitude as its
height, ensuring that the subsequent paragraph is pulled up to the same
horizontal level.  The container is filled with floats, whose containing
block is thus /not/ the paragraph.  Some lines of the container contain
just a left float; some just a right float; and others both a left float
and a right float.

In Firefox>=3 and IE8, no line boxes are allowed to be to the left of a
left float or to the right of a right float: we see from the alternating
text lines and blank lines that there are some places where the leftmost
float is a right float, and a line box is permitted sit to the left of
it; there are some places where the rightmost float is a left float, and
a line box it permitted to sit to the right of it; and there are other
places where two floats sit side-by-side but neither is as just
described, and no line box is permitted to sit on the same horizontal
level as those two floats, even though there is room.

In all recent versions of Opera, strangely, just one word is rendered to
the right of the float on lines where the the rightmost float is a left
float, but no line boxes are permitted to sit on other lines.

Safari 4 behaves the same as Firefox and IE8 provided that the content
area height of the container is non-zero and the floats overflow the
container's content area, else the floats have no effect on the line
boxes of the paragraph.[4,5]

In IE6, IE7 the floats have no effect on the line boxes of the paragraph.

The only relevant text in the current version of the CSS21 spec is the
following quote from 9.5 (Floats).[6]  It is clear that this part of the
specification only gives detailed consideration to floats in the same
containing block as the line boxes.  Given that Opera's behaviour is
clearly wrong, and Safari's seems to depend on strange conditions, which
of the two other behaviours (if any) is correct and/or meaningful?  The
spirit of the current spec seems to correspond to the behaviour of
Firefox/IE8 (certainly, floats in the same block formatting context but
in different containing blocks must not universally be ignored), but in
either case the description of the flowing of line boxes around the
float needs rewording and clarification. [In fact, it does anyway since
the heuristic for determining whether a float fits on the current line
is incorrect (email to follow).]

   # A float is a box that is shifted to the left or right on the current
   # line. The most interesting characteristic of a float (or "floated"
   # or "floating" box) is that content may flow along its side (or be
   # prohibited from doing so by the 'clear' property). Content flows
   # down the right side of a left-floated box and down the left side of
   # a right-floated box.
   #
   [...]
   #
   # 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. However, line boxes created next to the float are
   # shortened to make room for the margin box of the float. If a
   # shortened line box is too small to contain any further content, then
   # it is shifted downward until either it fits or there are no more
   # floats present. Any content in the current line before a floated box
   # is reflowed in the first available line on the other side of the
   # float. In other words, if inline boxes are placed on the line before
   # a left float is encountered that fits in the remaining line box
   # space, the left float is placed on that line, aligned with the top
   # of the line box, and then the inline boxes already on the line are
   # moved accordingly to the right of the float (the right being the
   # other side of the left float) and vice versa for rtl and right
   # floats.

Further test cases can be found in [7,8].  All browsers behave much as
expected given their behaviour with respect to [3,4,5].

[Epilogue: since at most one line box is allowed at any given horizontal
level, Eric J succeeded in simulating "float:center" buy making cunning
use of (the same) almost-zero line-height on the P and on the full-width
floats so that when the text bleeds out of the tiny line boxes it
visually appears at the same horizontal level on either side of the
floats. Very imaginative!]

[1] http://www.sitepoint.com/forums/member.php?u=180317
[2] http://lists.w3.org/Archives/Public/www-style/2009Jan/0445.html
[3]
http://dev.moonhenge.net/css21/test-cases/floats/line-boxes,floats,containing-blocks-1.html
[4]
http://dev.moonhenge.net/css21/test-cases/floats/line-boxes,floats,containing-blocks-2.html
[5]
http://dev.moonhenge.net/css21/test-cases/floats/line-boxes,floats,containing-blocks-3.html
[6] http://www.w3.org/TR/CSS2/visuren.html#floats
[7]
http://dev.moonhenge.net/css21/test-cases/floats/line-boxes,floats,containing-blocks-4.html
[8]
http://dev.moonhenge.net/css21/test-cases/floats/line-boxes,floats,containing-blocks-5.html

Cheers,
Anton Prowse
http://dev.moonhenge.net

Received on Monday, 24 August 2009 20:38:49 UTC