Finer details of floats

The other day I was working on one of those two column layouts. I quickly got into trouble by something I thought was a bug. It was a bug, but not in the browser(s) I thought. Let’s go.

A two column layout I said, but this one was a bit different. Each column consisted of a number of boxes, much like a newspaper kind of layout. I wanted the boxes ordered a bit different though: Content editors on the site ordered articles by importance in a single list and when that was transferred to a two column layout I wanted the second most important article to the right of the first article rather than below it. In the HTML source the boxes were ordered like the editors wanted and my job was to make them display in two columns.

Number 1 to the left, number 2 to the right, number 3 below number 1 to the left, number 4 below number 2 to the right and so on...

“This can’t be that difficult” I thought and floated all odd numbered divs to the left and all even numbered divs to the right. Behold the huge gap on the left side. I was stumbled. IE displayed it like I thought it worked, Firefox and Opera both displayed the gap (note to self: it’s seldom a bug if both Fx and Op display it the same).

So, where does the gap come from? I went looking in the CSS specification on float positioning and found an interesting list of the rules that govern floats. As with almost all specifications they are not meant to be easy to read, so made a version of them where I use some sample code to explain each of the rules.

This is the sample code you need to have in mind:


HTML:

...
...


CSS:
#child { float: left; }
#child2 { float: left; }

  1. #child and #child2 must stay to the right of #parent’s left border.
  2. #child2 must be to the right of #child since #child is earlier in the source. If there is not enough space to the right of #child, #child2 must be moved below #child instead.
  3. If #child2 was floated right and #child and #child2 could not be fitted on the same line, they still must not overlap.
  4. #child and #child2 must stay below #parent’s top border.
  5. #child2’s top border may not be higher than #child’s top.
  6. If #child was display: inline; #child2 must still not be above it.
  7. With #child and #child2 both floated left on the same line, #child2 may not stick out outside of #parent’s right edge, unless it is already as far to the left as possible.
  8. #child and #child2 must be placed as high as possible
  9. #child and #child2 must be placed as far to the left as possible.

The tricky one here is rule 5. It means that if #child was moved down for some reason, #child2 will have to move down too. Check the example again. See the space above box5 and compare it to the top of box4. Box5 can’t be above box4 according to rule 5 above. This is clearly what’s going on here. If we made box2 smaller than box1 there would be a space above it by the same reason.

Note that the list of rules is a prioritized list; rules earlier in the list are more important than the latter ones. To Internet Explorer, rule 8 seems to be more important than rule 5. Strange move by IE.

I hope this gave you an “Aha!” feeling, it certainly gave me.

16 responses to “Finer details of floats

  1. Yeah indeed, good to know this subtlety. That’s the kind of things you never know until you encounter a problem related to it cause you seriously can’t know all the specs (which are like you wrote “not meant to be easy to read”)

  2. I don’t agree with Rowan. I think it’s a bit obvious. The specs are logical this way, and I can’t think why it shouldn’t be that way.

    I agree that it could be a problem, and I believe there isn’t a solution, without JavaScript, or some kind of future conditional CSS.

  3. Let me explain a little more, by doing this they have removed a chance to make CSS more flexible, what they should have done is written it to behave like Internet Explorer unless clear: *; had been set.

    This would let us choose how we want the design to work, because I can see that both options are useful.

  4. I think the reason for this rule has to do with making the rendering faster. Progressive rendering perhaps?

    It’s not too bad in my opinion, putting the boxes in two “column divs” was easy enough (even though that gives another source order).

    As long as browsers render things _one_ way, whether that way is good or bad, I’m all happy :)

  5. So, just curious, what did you end up doing to get the layout you wanted?

  6. @Jennifer Grucza: I ended up looping over the list twice server-side and build two lists of content. Each list was wrapped in a div and of course displayed appropriately. I’m pretty sure it can be done using some other method but I simply didn’t have the time to experiment more. This made everything work like it should except none styled browsers, they got the content in the wrong order.

  7. Shouldn’t going over it once be enough? Something like this:

    1. Create an array from the list
    2. Create a second array
    3. Loop over the first list once and for each item: if number is odd copy the item to the second list and after that delete the item in the first list.
    4. Print each list in the correct wrapper.
  8. Pingback: a.css, esbudellant estàndards » Engraellat de caixes
  9. At the end of rule 2:
    ‘#child2 must be moved below #child2 instead’ should read ‘#child2 must be moved below #child instead’, no? ;)

Comments are closed.