Flexible Layouts with CSS Positioning

This article was prompted by the growing crop of CSS “tips and tricks” articles that have surfaced in the last two years. Typical of these are the three column design making use of left and right fixed columns hanging on their margins; and the use of @import, instead of JavaScript, to feed appropriate style sheets to differently enabled browsers.

Article Continues Below

These ideas are very cool and their authors should rightly be heaped with praise, but I can’t help feeling we’ve been here before.

Remember when you figured out how to make a table of images display without the gap? Or how about when you worked out the browser’s table rendering algorithm and started using “educator” rows to guarantee correct display? Even more sinful, do you remember discovering those “hidden” (non-standard) attributes like marginwidth?

As web designers, we are naturally drawn to tricks, gimmicks, and workarounds. We need to keep our attention on what we are trying to achieve in long run.

Real world problems#section2

  1. I want my designers to use CSS. I don’t want them to hide behind WYSIWYG applications, I want them to truly understand what they are doing.
  2. I want universal, flexible layouts. Ideally, a line of text should be as long as certain number of characters, not some arbitrary pixel measure. I want my designers to create grids that are both intelligent and beautiful. I want my client’s information to be as useful on a 160×160 PDA screen as it is on a 1024×768 PC monitor.
  3. I need the team to spend less time on CSS hacking and more time on direct design implementation.
  4. I need flexibility in grid design. If the concept suggests a six-column grid, then I get a six-column grid. Ditto if it needs to be an eight column section on top of a four column section.

Setting practical restrictions#section3

In searching for the most practical grid-building technique, I’ve imposed some restrictions on myself. These are to do with defining the practicality of the solution for my chosen environment (the design studio) and the people who will use and develop these techniques (Dreamweaver-loving designers).

  1. Some browsers understand the @import directive but not the box model (iCab in particular is a fantastic browser in all but CSS2) so ideally, @import hacks shouldn’t be used.
  2. If there must be filtering to alternate style sheets (often unavoidable) then they should be as similar to each other in structure as possible. In particular, if properties are applied to IDs then the same ID selector should appear in all the alternate style sheets to make changing/developing the grid easier for designers.
  3. Again in the interest of designer-friendliness, every box in the grid should be explicitly named, to allow the applying of typographical or border effects without having to add a selector.

Possible solutions#section4

I’d like to suggest a couple of design methods that go a little way toward satisfying the requirements listed above. Think of these as a bridge to that point two years from now when all designers are trained to think natively in CSS.

For starters, here is how a designer describes a three part multi column layout:

  
content stuff here
content stuff here
content stuff here
content stuff here
content stuff here
content stuff here

In the designer’s head, he has just created the XHTML structure for a one-column top (news introduction?) and a four-column (main stories?) bottom section with a one-column footer. He wants the middle and bottom sections to happily float up and down the page in response to the user’s font size selection without any sections overlapping.

Simple enough, really; now why must he go any further?

He should be able to add any number of columns without the page falling apart and without having to go through serious brainy positional coding.

Another thing—it makes sense to write your DIV structure in the order that you intend the reader to read it, not some back-to-front thing to accommodate a weird backwards-compatibility glitch. The idea is to make creating structured layout as simple as possible.

Absolute v. relative positioning#section5

As far as I can tell, there are two ways to do this. Both make use of the basic “absolute” and “relative” positioning attributes. Where a lot of people get this wrong is that the CSS Box Model defines a position:absolute block as absolute relative to its containing block, and not relative to the page or window.

In our example, this means that a set of four absolutely positioned DIVs can line up inside a container DIV defined as relative, and still float up and down on the page in response to font-size changes — all the while retaining their position in relation to each other. Not only that, the layout holds together regardless of the number of columns.

In theory, we’re done. As ever in web design there has to be a bug and some hacking in response. I outline two methods to implement this grid below. Neither is perfect. One uses JavaScript to manually force a parent DIV to inherit its child’s properties (more later); the other has the simplest possible CSS definition, but requires a sniff to send IE5/Mac a different style sheet.

Method 1: CSS only#section6

Our first method is pure CSS and assumes that the designer or site editor has planned an element of copyfitting into the layout. In practical terms, this might mean knowing that the “Blog” section in the middle of the page is always going to be longer than the nav on the left — not an unreasonable request, in my book.

Here are the main containers defined:

  #top-section {
  position:relative;
  left:0;
  top:0;
  }
  #mid-section {
  position:relative;
  left:0;
  top:0;
  }
  #bottom-section {
  position:relative;
  left:0;
  top:0;
  }

Nothing unusual at this point, except those of you who are familiar with the absolute/relative property will have worked out that these containers will not expand when filled with absolute DIVs.

For these sections to expand — for “mid-col-1” to start just beneath “top-col-1” and above “bottom-col-1” — the three container DIVs must either contain relative DIVs or their height must be calculated and applied by hand.

In this method, the design says that the largest column in the middle section is “mid-col-2” so we set mid-col-1,3 and 4 to absolute, and mid-col-2 to relative. Top and bottom sections contain one relative DIV each, so no problem there. This is what the style sheet looks like:

  #top-col-1 {
  position:relative;
  padding-left:20%;
  padding-right:10px;
  }
  #mid-col-1 {
  position:absolute;
  top:0;
  left:0;
  width:20%;
  }
  #mid-col-2 {
  position:relative;
  top:0;
  left:20%;
  width:40%;
  }
  #mid-col-3 {
  position:absolute;
  top:0;
  left:60%;
  width:20%;
  }
  #mid-col-4 {
  position:absolute;
  top:0;
  left:80%;
  width:20%;
  }
  #bottom-col-1 {
  position:relative;
  padding-left:20%;
  padding-right:10px;
  }

This works well in most standards compliant browsers, but not in IE5 Macintosh Edition, which is the browser I use every day.

The bug has something to do with the calculation of width percentages in a relative container. If you set mid-col-2 to “absolute,” the problem goes away.

Method 2: Passing the height of an absolute DIV to its relative parent#section7

If you choose to go with all columns set to absolute, now you have the problem of “bottom-section” overwriting “mid-section”.

The workaround I am currently playing with involves a small script. (It is currently on the clunky side, so for now I’m using the CSS-only method above.) The trick is to use the onload event handler in the <body> tag to trigger a little script that reads the height of “mid-col-2” and passes it to “mid-section.” This forces “bottom-section” to start further down the page where it’s supposed to.

The following scripting is bare minimum. (It would be more elegant to have a script that walks the document’s DOM tree, applying itself to every container of a certain type. In this way you might pass the height of the longest column instead of arbitrarily passing only “mid-col-2” and you could perform the transfer to any number of relative container DIVs.) If a clever JavaScripter wants to finish the job, I’d be obliged. In the mean time, here’s the little hack:

  function inherit(objidParent,objidChild,objidGrandchild) {
if (document.layers) {
alert('sorry, no pretty layouts for netscape 4');
}
else if (document.getElementById) {
  
Parent = document.getElementById(objidParent);
Child = document.getElementById(objidChild);
Grandchild = document.getElementById(objidGrandchild);Parent.style.height = Child.offsetHeight + 'px';
Grandchild.style.display = 'block';return true
}
  } 

With this method, “bottom-section” is at first invisible to prevent slower machines from displaying the overlapping DIVs:

  #bottom-section {
  position:relative;
  left:0;
  top:0;
  display:none;
  }

After assigning the height of the child to the parent, the script sets the display attribute to “block” — completing the layout.

You could further refine this by calling the script every time you run
“styleswitcher” to keep the footer from losing its position on application of the new style sheet.

Moving on#section8

I wanted to achieve a grid system that would let my designers move more quickly and so produce fresher work. Ultimately, the only purpose of a grid system is to be broken. As we come up with these web design ideas, we tend to copy each other and everything tends to look the same. This is my main problem with Flash: the typographic animation routines are so cool, everybody uses them.

You can see a functioning example of this grid system on my web log donkeyontheedge.com, and yes, I guess it does sort of look like everybody else’s.

About the Author

Dug Falby

Dug Falby is a designer. He lives in London with Nicki and Clementine. At night he dreams of gold pencils, but in the morning he focuses on breakfast.

119 Reader Comments

  1. I’m building a page accoring to the XHTML Mobile Profile. Is it possible to use the “top” and “left” attributes for a div?

  2. I read this article and all I could find on the net about CSS, tables replacement by DIVs, and so on … To my minf this is too prematured to use such techniques with all browsers having problems with the standard. That’s why I don’t understand why you are all crazy about CSS. CSS is good for formatting, it’s not yet for layouts.

    I tried all the techniques to build a 3 columns layout. Each time when reducing the window width, the 3rd column goes under the 2nd one. I can’t even imagine producing a site where my visitors would say : this is not serious.

    So I will stay with tables until something serious comes up in browsers. This day, I will convert.

  3. I have read this article and CSS Design: Taming lists. Great info and very informative, but now I’m looking beyond for a new solution. I have my list of links on the left hand side of the web page, common. I’m got some content in the center of the page, and I want to wrap the bottom across the bottom of the content. We’ve all seen it before, and I know it can be done with pretty pictures: a nice bar on the left that bends at the bottom and juts to the right. Now the question, how do I do his with CSS?

  4. Well, I like Firebird for it is much lighter then mozilla/netscape but on the other hand it has the exactly same problems rendering my website. I don’t know if the problem is with IE/OPERA (for it displays correctly and the same in both) or with Firebird but since IE community is the largest and I personaly am using OPERA 7.11 I won’t switch until the rendering of CSS is improved.
    I do have all of them installed for experiments and I try really hard to get standard, and I am (according to XHTML transitional validator), but MOzilla/Firebird always position my divs a bit lower then it is supposed.

  5. I read that the

    position: absolute

    doesn’t mean that the position (right: left: top: bottom:) is relative to the entire window, but it is relative to the innermost block containing the element! Is this right?

    I thought the
    position: absolute
    made these distances (right: left: top: bottom:) relative to the entire document, an the
    position: relative
    made these distances relative to the innermost block element!
    Was it wrong?

    if so, the html (with CSS) below should work fine, but it doesn’t!

    ——
    css:

    .container
    {
    background-color: Green;
    padding: 5px;
    }

    .content
    {
    background-color: Red;
    padding: 5px;
    width: 200px;
    right: 3px;
    position: absolute;
    }

    html:



    here text


    —–

    as you can see, the .content div overlaps the border and goes outside the .container! what’s wrong?

    thanks.
    Mattia

  6. Hi,
    I have a fixed layout of 760 width. I’m using CSS2 to place the buttons in the top nav whose link’s and text come thru server side. Now it requires a line to stretch in the end and only appear when there are less links on the top navigation. As it is dynamic, the line also needs to stretch acordingly hence i don’t want the width for the line to be defined. Just now my code has it. Below is the code for both the HTML and CSS. Browser supported are IE5.0 and above and Netscape 6.1 and above. Please help as soon we are entering to UAT and i still don’t have a fix for it.

    HTML :

    CSS:
    .button {
    color: #ffffff;
    background-color: #99cc00;
    height:15px;
    font-family: Arial, Verdana, Helvetica, sans-serif;
    font-size: 8pt;
    font-style: normal;
    font-weight: bold;
    text-align: center;
    text-decoration: none;
    padding: 2px 5px 2px 5px;
    display: block;
    float: left;
    border-top: 1px solid #99cc00;
    border-right: 1px solid #99cc00;
    border-left: 1px solid #99cc00;
    border-bottom: 1px solid #009900;
    }

    .button:Hover{
    color: #ffffff;
    background-color: #009F00;
    height: 15px;
    padding: 2px 5px 2px 5px;
    text-decoration: none;
    font-weight: bold;
    border-bottom: 1px solid #009900;
    border-top: 1px solid #009900;
    border-right: 1px solid #009900;
    border-left: 1px solid #009900;
    }

    .button1{
    color: #009900;
    background-color: #ffffff;
    height: 15px;
    font-family: Arial, Verdana, Helvetica, sans-serif;
    font-size: 8pt;
    font-style: normal;
    font-weight: bold;
    text-align: center;
    text-decoration: none;
    padding: 2px 5px 2px 5px;
    display: block;
    float: left;
    border-top: 1px solid #009900;
    border-right: 1px solid #009900;
    border-left: 1px solid #009900;
    }

    .padding{
    width: 2px;
    float: left;
    background-color: #ffffff;
    border-bottom: 1px solid #009900;
    padding: 0;
    margin: 0;
    height:20px;
    }

    .bBottom{
    border-bottom: 1px solid #009900;
    float:left;
    height: 20px;
    width: 29.5%;
    overflow: hidden;
    }

    .vertical6{
    padding: 0;
    margin: 0;
    height: 3px;
    overflow: hidden;
    }

    Thanks
    a

  7. Anu, try taking out the width parameter in the bBottom class. Leaves a samll tail in Moz Firebird when I do this.

  8. I do write some tosh. The small tail was, of course, the padding at the end of the buttons. I made the following work for me, you will need to modify the Hover to suit.

    body {
    margin:10px 10px 0 10px;
    padding:0;
    background:white;
    }

    .button {
    color: red;
    background-color: #CCC;
    height:18px;
    font-family: Arial, Verdana, Helvetica, sans-serif;
    font-size: 10pt;
    font-style: normal;
    font-weight: bold;
    text-align: center;
    text-decoration: none;
    padding: 2px 5px 2px 5px;
    display: block;
    float: left;
    border-top: 1px solid blue;
    border-right: 1px solid blue;
    border-left: 1px solid blue;
    border-bottom: 5px solid black;
    }

    .padding {
    width: 5px;
    height: 18px;
    padding: 2px 0px 2px 0px;
    float: left;
    /* background-color: #ffffff; inherit ‘body’*/
    border-top: 1px solid white;
    border-bottom: 5px solid red;
    margin: 0;
    }

    Don’t need to call the bBottom class.

  9. Here is a slight modification of Justin’ script. I’m far from a Javascript/DOM expert, so here is my attempt to get it right.

    The difference in this script is it looks for a div element with a class named ‘container’. Inside the container you have your children div elements. The script calculates and sets the height for the container div, then goes finds the children div elements of the container and sets their height as well.

    In the body element put onload=’balanceContainer()’ and thats it. It should work in IE 5.5+ and any Mozilla browser. Works in IE6/Mozilla 1.4, but haven’t tried it in Opera/Konqueror/Safari yet though.

    =====================
    function parseContainer(div) {
    var tLength=0;
    var nLength=0;
    var childNode;
    var children=div.childNodes;
    for (i = 0; i < children.length; i++) { childNode=children.item(i); nLength=childNode.offsetHeight; if (nLength > tLength) { tLength=nLength; }
    }
    div.style.height = tLength + ‘px’;

    /* Parse again -> Insert offsetHeight to all children */
    for (i = 0; i < children.length; i++) { setSubContainer(children[i],tLength); } } function setSubContainer(subdiv,length) { if (subdiv.tagName == 'DIV') { subdiv.style.height=length + 'px'; } }

  10. How about this… Setup three main divs called top, middle and bottom. The top div is absolute at the top of the page/screen, the middle is relative to the bottom of the top. The bottom is relative to the middle.
    So the middle and bottom divs are relatively positioned vertically.

    Within the middle div (container), create the column divs (1 to 4). The column divs are relatively positioned horizontally. If we assume that each column div is evenly spaced then they would be 25% of the width of the container div.

    Is what I’ve described above impossible to do with divs, CSS, and without tables? Is is possible for a div to automatically expand in the way that table cells do. If divs can expand the way table cells do, then do relatively positioned divs, automatically readjust their based on other elements within a document… specifically other divs?

    I’m hoping the answers are yes, yes, and yes. If not please explain.

  11. hmm isn’t all this suposed to be geared towards accesibility? some areas of info on this page (i.e. samples/examples of code) are spread all over the place. Just thought i’d let you kno and ask if anyone knows why.

  12. http://webforums.macromedia.com/dreamweaver/messageview.cfm?catid=189&threadid=735071

    I just discoverd that the topic how to get a DIV to expand its container DIV or other element is discussed here aswell. I posted the similar on the Macromedia forum this friday . One partial solution is to float the child DIVs but then I had to REMOVE absoulte positioning on those DIVs. Can you belive that! Flexibel layout consepts are something I have to deliver. And pushing the child DIVs around with padding and borders is not good.

    What is the Übersolution to follow folks?

    Erland FLaten, Lillehammer Norway.

  13. >>An interactive page such as a web page is an application.

    if this is the case why dont we have a browser that works like the adobe acrobat interface, removing navigation into a side bar.

    If you could somehow declare to a user agent what is your navigation or even a site index, ‘footer’ information and all that other standard stuff it’s display could be removed from the ‘web’, ‘pda’, ‘mobile phone’ screen.

    Why do we need to write an ‘application’ every time that we want to publish something? I thought the browser was supposed to be the application.

  14. i don’t know how to search ALA to see if the issue has been raised and it does kind of relate to my last point.

    Taking a wedge of text and shoving it in both a html page without formating and a pdf file with formating the resulting file sizes were 12k and 16k.

    I guess the extra code needed for the layout in the html and css would bump it up 2 or 3 k, and still would do well to get close to the amount of control you have laying out the pdf, and you have control of font face and sizing and printing.

    Is it not the case that pdf could be a viable alternative to html – especially for sites that are no more than a company brochure. For dynamic sites I dont know, I believe you can have forms in pdf? but I dont know how they can be generated on the fly.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA

I am a creative.

A List Apart founder and web design OG Zeldman ponders the moments of inspiration, the hours of plodding, and the ultimate mystery at the heart of a creative career.
Career