Clear Positioned Elements
Update
A revised script that addresses the issues brought up in the comments of this post and a subsequent post on the same topic is available for discussion in Absolute Clearance.
The Thought
Paraphrasing one of Mike Davidson’s comments on Andy Budd’s alarming (but painfully realistic) An Objective Look at Table-based vs. CSS-based Design:
The CSS spec (or browser makers’ implementation of it) should not take absolutely positioned elements completely out of the document flow. You should be able to put two absolutely positioned columns inside a master div and then create divs after that master div which appear unconditionally below those two columns…
And as long as we can chose between this new behavior or the equally powerful, traditional behavior I am in complete agreement. So I whipped up a simple script that allows us to do just that. It forces a relatively positioned element (just <div>
s at this point) to expand and, in effect, “clear” the contents of the absolutely positioned elements contained with in it—regardless of their depth.
Here’s a very simple header/two column/ footer example and a more complex example featuring multiple nested cleared absolutely positioned elements.
To implement this technique, just attach the JavaScript to your document. (If you have other scripts that run onload
you will want to remove the last line, window.onload = SI_clearAbsolutes;
and add a call to SI_clearAbsolutes();
in your initialization function.) Then add a class of si-clear-absolutes
to any elements that contain absolutely positioned columns. That’s it.
An Afterthought
View source on that last example. What does that structure look like to you? A table, right? Funny, that. The code comes round full circle. Along with the obvious drawbacks (disable JavaScript and have a look at the examples), there’s something unsettling about using a custom script with custom tags (in this case, a custom class on standard <div>
tags) to recreate the effect of a standardized HTML element—which brings us back to Andy’s original post. Your thoughts?
014 Comments
…but can you vertically center the text in these divs? You can do it so easy with tables, but it always seems a nightmare with divs. When I need to do it, I always end up going to a table because it takes me 3 minutes. I love using no tables, but I think everyone agrees (even Zeldman) that tables are a necessary evil while browsers do not render CSS perfect.
Also, after having to put all those extra tags in there (plus a javascript) to make this simple concept work, is there any advantage to using divs here? It seems a table would work much better in the end for cross-browser (and people with js disabled).
Yeah, that is very interesting. When I was working on the previous design of my site I ran into this problem.
I ended up solving it for my site by using a master div to contain my content, footer and menu divs. Setting position relative on my container div with 0 values for left and top; floating the menu div left, and then creating the footer CSS with no positioning info at all gave me the effect I wanted.
Probably not the best solution, or the most elegant but hey it worked. I am using a modified version of this on the current layout, sans a menu div.
Love the site, and your topic choices by the way/.
Or alternatively, you could use floats to get both these effects without relying on JavaScript and wihout it looking like a table. If you’re clever enough you could also manage without any empty DIVs to clear the floats.
Thanks Chris. Josh, excellent point about vertical alignment.
The main benefit is semantic purity and separation of content and presentation. But the dependence on JavaScript and what amounts to emulating tables has me on the fence. I think this would be perfect for a web design-oriented portal though when you can be almost certain that your visitors have JS enabled.
I forgot to mention in the post that a
<noscript>
tag could be used to import a stylesheet and unposition the absolute elements. It may not be pretty but content wouldn’t overlap at least.Ah yes. Footers that stick to the bottom until the content exceeds the viewport.
Someone has made a pure css version, no javascript at all (which I find a Really Good Thing (tm) in this case). It claims to work in IE, Firefox 0.8, Safari 1.2 and Opera 7.5.
You can have a look at it here: http://www.cafejansenenjansen.nl/got/test4.html
(no I didn’t make it myself, but it has surprising little css code to get the basic form in place..I’ll see if in can make a example with less cruft.)
Chris and Rick: The benefits of absolutes over floats are that they are far less finicky, buggy, and fragile, and also that they free your source-order up a little bit. Floats were never meant to position long columns of content, but rather to shove peripheral items off to the side and have text flow around them. Yes, they can be used for columns, but if we’re going to question the “original intent” of a table, we must also question the original intent of floats.
Akaxaka: The example you referenced is a very good one, but it addresses a different problem than is addressed here. The problem your reference addresses is pinning a footer to the bottom of the viewport if the content isn’t long enough. The problem Shaun’s code addresses is that once you position two columns next to each other, using absolutes, you don’t have access to “the bottom most point” of those two collective columns… meaning, you can’t place content (i.e. a footer) below both of them reliably without using Javascript.
Mike D.: Of course you don’t have access to “the bottom most point” of those two collective columns!
The trick is to place the footer within the (absolutely positioned) holder of the longest collumn and then to give it a top margin. that’s the same as it’s height.
Sure, it’s nested, but I’d prefere it over JS, evernthough 94% of people have JS switched on…
Akaxaka: Again, you are correct, but that is the exact problem we are trying to solve here. To require that one column always be the longest is not a requirement many are comfortable making.
In the simple example of a two-column blog, you can require that your peripheral column be the longest, but then you can’t ever post any long blog entries. Or, you can require that your main column be the longest, but then you can’t post any short blog entries. Varying font sizes complicate the issue even further. The crux of this exercise is as the post title states: how to clear positioned elements.
i have to say this is a very nice piece Shaun. But it is a shame that javascript is needed, but hey those are the breasks.
Still nice job.
Nice work, Shaun … But I’ve got to confess I’ve never been terribly interested in fixed-width layouts. Is there a way to make the #footer clear when the absolute DIVs are defined in percentages?
I’m having the longest DIV flow underneath the #footer when the window is resized.
The hoops we must go through to do what a TABLE did so simply! . . And we still can only . I really think Andy gave us “permission” to say what we feel. Years after the implementation, there still is not a single method to my knowledge of creating an automatically-adjusting, liquid layout that works consistently on all browsers, sans scripts and hacks.
I’m trying to rebuild my own site, in pure CSS, and it’s slow going. I did a1professionalpainters.com with a TABLE with four cells. Not just easier, but better!— the layout works consistently, from NN4 to Konqueror.
God bless Hakon Lie for giving us CSS, but the man never seemed to be thinking at all of how to display anything other than a single column. Now, instead of abusing tables with needless nesting, we hack up our CSS, and fill our XHTML with strangely non-semantic nested DIVs.
<sigh>
.Anyway, if you could help regarding a liquid version, I’d appreciate it!
Jon
THE TRUTH IS OUT!
What does Hakon Lie, the inventor of CSS, use for a 2-column layout on his own page???!
TABLES! w3.org/People/howcome/d/9707-vestland
Jon
Adding a class to the div is, IMHO a bad idea. Also, its much nicer to simply drop in a jsp without having to munge your inline javascript.
This idea comes from some of the work that dean edwards is doing on ie7 (http://dean.edwards.name/ie7), although I wouldn’t use behaviours since they are limited to IE.
What I would do is add a custom CSS property (-position-model or something similar) and have my scripts look at the css to see which blocks need to use the special code.
And I think that you might be able to do the following in your script and remove any requirement for modifying the existing code:
Although it may depend on where you put the script tag.
Hoorah, it worked for us!
(Drew & Nathan from Mirashade are thankful!)
This is a nice proof of concept, but I wouldn’t deploy it on a live site. Aside from the JavaScript requirement, it also breaks when you resize text because the position of the elements has been calculated with the size of the text taken in to account.