This article
originally appeared in the Design & Usability Tactics newsletter. Click
here
to subscribe automatically.

Developing attractive and effective
page layouts with CSS is an ongoing challenge. A recent project required an
interesting combination of techniques in order to achieve the design
objectives, and combining those techniques in the same layout presented some
challenges. The biggest one was finding a solution that works—not just in
theory—but across multiple browsers in the real world. The solution, though
relatively simple in retrospect, required considerable trial and error to
achieve.

The layout

The page layout (Figure A)
consists of a header over a two-column body, with a footer at the bottom. It’s
a liquid layout that automatically resizes with changes in the browser window,
and the major layout elements are centered on the page.

The header, which includes a logo, a
picture, and a navigation bar, is what puts an interesting wrinkle in this
layout. The logo is flush left, while the picture and navbar are flush right.
This allows the header to expand and contract in width while remaining flush
with both sides of the body area below. The navbar extends under the logo to
tie the left and right sides together.

The body area includes a fixed-width
sidebar column on the left and a variable-width main column to the right. The
footer at the bottom of the body area spans the full width of both columns.

The code

To position all those elements
properly, I create separate divs for each of the layout elements (logo,
picture, navbar, sidecol, maincol, and footer) plus two wrapper divs: one
(bodywrap) to enclose the sidecol, maincol, and footer divs, and another outer
wrapper (master) around everything to allow for centering the layout on the
page. The various divs use a combination of static, relative, and absolute positioning.

Here’s the XHTML markup for the
example page in Figure A:

<body>
<div id="master">
    <div id="picture">Picture</div>
    <div id="navbar">Navbar items go here</div>
    <div id="logo">Logo</div>
    <div id="bodywrap">
        <div id="sidecol" >
            <h3>side</h3>
            <ul>
                <li>Let me not to the marriage of true minds</li>
                <li>Admit impediments; love is not love</li>
                <li>Which alters when it alteration finds</li>
                <li>Or bends with the remover to remove</li>
                <li>Oh, no, it is an ever fixed mark</li>
            </ul>
        </div>
        <div id="maincol">
            <h2>main content</h2>
            <p>That looks ... height be taken.</p>
            <p>But bears ... alteration finds.</p>
            <p>Whose worth's ... to remove.</p>
        </div>
        <div id="footer">
            <p>Footer text goes here </p>
        </div>
    </div>
</div>
</body>

Here’s the CSS code that makes the
layout work:

body {
    margin: 0px;
    padding: 0px;
    background-color: #666666;
    font-family: Verdana, Arial, Helvetica, sans-serif;
    font-size: 12px;
    text-align: center;
}
#master {
    position: relative;
    width:90%;
    margin-left: auto;
    margin-right: auto;
    margin-top: 20px;
    background-color: #006600;
    text-align: left;
}
#logo {
    position: absolute;
    width:200px;
    height:125px;
    top: 0px;
    left: 0px;
    background-color: #FF0000;
}
#navbar {
    position: absolute;
    height:35px;
    width: 100%;
    top: 92px;
    right: 0px;
    text-align: right;
    background-color: #CCFFFF;
    line-height: 35px;
    border-bottom: solid #000000 2px
}
#picture {
    position: absolute;
    height:92px;
    width: 500px;
    top: 0px;
    right: 0px;
    background-color: #0000FF;
}
#bodywrap {
    background-color: #FFFFFF;
    margin-top: 150px;
    position: absolute;
    padding: 20px;
}
#sidecol {
    width:200px;
    float: left;
    background-color: #FF6666;
    margin-bottom: 20px;
    padding: 5px;
}
#maincol {
    margin-left: 230px;
    background-color: #99FF66;
    margin-bottom: 20px;
    padding: 5px;
}
#footer {
    width:100%;
    height:30px;
    clear: both;
    padding: 10px 0px;
    text-align: center;
    color: #000000;
    background-color: #FFFF99;
}

Centering the layout

The body style zeros out the margins and padding, sets the background
color, and establishes default fonts. The text-align:center
rule is for the benefit of IE5.5/Mac and allows that browser to center the
layout elements on the page.

The #master style formats the outer wrapper div, which provides a
container for the other elements, sets the overall margins, and centers the
layout. The position:relative rule
makes sure the absolutely positioned child elements are placed relative to the
master div instead of the full page. The width:90%
rule, along with the margin-left:auto
and margin-right:auto rules, centers
the layout with a small space on each side, while the margin-top:20px rule adds a little space at the top of the page.
The text-align:left rule resets the
default text alignment that was changed in the body style.

Note that the background-color:#006600 rule creates a dark green background for
the master div, but you won’t see any of that color in the sample page. The
master div collapses to no height because the div contains no text or other
divs that are part of the normal flow—all the child elements are (or are
contained within) absolutely positioned divs, which exist outside the normal
page flow. However, the div still does its job of providing a position
reference for its child elements.

Constructing the header

The #logo, #picture, and #navbar styles each include the position:absolute rule along with size
(i.e., width:200px, height:125px) and position (i.e., top:0px, left:0px) settings. A background-color rule in each style
makes the divs visible in the example, but only the navbar contains a
background in the real page layout.

Note that the positioning of these divs’
is relative to the “master” container div. Therefore, the top:0px and left:0px rules position the logo div in the upper-left corner of
the master div, not the upper-left corner of the page.

The width:100% rule in the #navbar
style makes the navbar the full width of its parent element (the master div)
and the border-bottom:solid #000000 2px
rule adds a black horizontal line to the bottom of the div, which helps pull
the left and right sides of the header together. The #navbar style also includes rules to make the text flush right (text-align:right) and center it
vertically (line-height:35px, which
is the same value as the height of the div).

Using absolute positioning for the
logo, picture, and navbar allows you to position those elements against the
left and right sides of the master div, regardless of its resizing. Floats, on
the other hand, will collapse and drop down the page if the browser window
becomes too narrow. Absolute positioning is also necessary to allow the navbar
(and sometimes the picture) to extend behind the logo. This is an important
consideration because the logo’s background in the real Web site is
transparent, allowing the navbar and picture to show through. The left sides of
those elements are graduated to blend into the background behind the logo.

Building the body

The #bodywrap style formats the container div for the remainder of the
page–the sidebar column, the main content column, and the footer. Like the
header elements, it’s absolutely positioned (position:absolute) relative to the master div. It doesn’t have a
fixed size so it can expand with its contents, up to the maximum width of the
parent (master) div. The margin-top:150px
rule pushes the bodywrap div below the header with a little room to spare. A top:150px rule would do the same thing,
but margins seem to work more reliably. The padding:20px
shortcut rule sets equal padding on all sides of the div. That works for this
example, but you could also use margin settings on the child elements to
accomplish the same thing. Another option is to add a background image to this
wrapper div to create a full-height background for the sidebar column.

The #sidecol style establishes the fixed-width sidebar column with the width:200px rule and floats it to the
left (float:left). Floating the
sidecol div allows the maincol div to fill the space to the right of the
sidecol rather than positioning it below the sidecol div. The style also
includes settings for the background color, bottom margin, and padding, but
none of these settings affect the technique.

The #maincol style formats the main content column. The margin-left:230px rule creates space for
the 200-pixel-wide sidebar column, plus a comfortable gutter, and keeps the
content from flowing into the space below the sidebar. The background color,
bottom margin, and padding settings are just for appearance. In a real
application, you’d probably add other rules to this style to format the
contents of the column.

Finally, the #footer style formats the div at the bottom of the page. The width:100% rule makes the div the full
width of its parent element (the bodywrap div, which is the full width of the
master div). The clear:both rule
ensures that the footer is placed below both of the other columns by specifying
that it be clear of other elements on both sides. Note that the clear property
applies to peer-level elements within the same parent element (the bodywrap
div), not to other elements outside the parent. The other rules in the #footer style are for the appearance of
the sample and are optional.

Limitations

Essentially, this layout consists of
absolutely positioned divs within a relatively positioned div that is centered
on the page. Using absolute positioning provides good control over the
placement of those elements, but it leaves the container div empty of any
content that is in the normal flow.

As a result, the master div does not
expand vertically to surround the other page elements as you might expect.
That’s no problem for this particular layout, but it does create a few
surprises that could impact derivations of this layout.

For example, the background color
from the bodywrap div extends all the way to the bottom of the page. You might
expect to be able to change that by adding a bottom margin to the master div
since it seems to encompass the bodywrap div, but it doesn’t work because the
master div is just a horizontal line near the top of the page and the
absolutely positioned divs extend out the bottom of their container.