multilevel float

on
November 23, 2011

Last night I solved a problem that's been bugging me for years. It turned out the solution wasn't even all that difficult, yet somehow I never came across the correct implementation before and so I'd figured it just couldn't be done. To be honest, it made me feel quite stupid, at the same time it made me realize I'm probably not the only one struggling with this. So here's a blog post for all of you who've been trying to stack elements residing in different dom levels.

it's all about structure

You can actually witness the problem live on this page (at least for now, I'm planning to change this as soon as possible). Regular visitors won't notice it because it's not a visual issue, but if you dig into the html code you'll soon see that I ran into some serious structural problems here.

If you look for the article component you'll find it nested inside the left column, but if you check the top of the right column you'll find article info and visitor stats there. Currently both elements are connected by a matching background colors, ideally they should be nested within the same component. After all, article info and visitor stats can be considered meta data of the article. The assumed problem lies with the related page data that is placed directly below the article meta data (related article, articles, ...). Somehow I never found a way to layout this structure with the article meta data actually nested inside the article component.

floats to the rescue

<div class="wrap"> <article> <div class="main">...</div> <aside>...</aside> </article> <aside>...</aside> </div>

This is roughly the structure we're going to work with (a small abstraction of my current blog code). The goal is to have the article > .main area to appear to the left and to have both aside elements appear on the right, neatly stacked below each other without and javascript trickery or fixed css heights.

The key to solving this problem (and what I somehow missed completely) is to understand that floats will continue to work as expected even when they are set on different dom levels. My initial reaction to floats is to make sure their wrapping parent always clears the floats. In this case though, the article wrapper is simply a structural/semantical wrapper and its contents should not really be contained by it.

.wrap > article > .main {float:left; width:100px;} .wrap aside {margin-left:100px;}

It's really that simple. The article > .main area is floated left, while both aside elements are pulled to the right with a left margin spanning the width of the left-floated element. As a result they both appear beside the article > .main area, neatly stacked underneath each other.

see the code in action

support and pitfalls

Basic support for this method is superb. It works all the way down to ie6 with no extra fixes required. While this is great, it actually made me feel worse for not knowing about this simple trick.

There are some (rather serious) pitfalls though. You have to make sure that the article element does not clear its content, so no clearfix or overflow:hidden can be applied to this element. Other clearing methods are equally forbidden. Worse though is the fact that you can't apply any clearing within the aside elements as their contents will once again drop below the left-floated main area. This might be a big issue when working with more complex use cases.

.wrap > article > * {float:left; width:100px;}

Finally, you could lose the .main wrapper inside the article element (placing the float and width properties on article > *) if you're a real html purist, but that means you'll end up with a lot of floated elements that won't collapse their margins and will generally behave in unwanted ways, that's why I left the wrapper in there.

conclusion

So there you have it, a simple and browser-proof method to create the proposed layout with the given html structure. Many of you will wonder how this could've escaped me all these years, I don't really have an answer either. I can only assume that this isn't common knowledge, which is why I wrote this little piece.

As for more "modern" methods, I assume it's also possible to fix this layout using the css3 grid layout module, if anyone could point me to an interesting article regarding this subject I would appreciate it a lot.