6.2. Perfecting Multi-Column Layout

In Chapter 5, I showed you the basics of multi-column layout with absolute positioning. Unfortunately, that technique seemed to run into a virtual dead end when it came to putting a footer beneath the columns. The uneven column heights, combined with the fact that the footer will always appear directly beneath the center column, meant that the left and right columns could overlap the footer in a most unattractive manner (see Figure 6-6).

Figure 6-6. The Problem with Absolute Positioning for Multi-Column Layout

To solve this, we need to find a way to make the center column extend if needed to match the height of the longest column. In short, we need to equalize the column heights to match the one that contains the tallest content. And while absolute positioning alone cannot do this, there are at least two methods that can…

6.2.1. Equalizing Column Heights with DHTML

If absolute positioning with CSS alone can't achieve the desired layout, then one option is to use Dynamic HTML[2] (DHTML) to adjust the layout as needed. In this section, I'll show you how some simple JavaScript code can adjust the "broken footer" layout in Figure 6-6 so that the three columns are of equal heights and the footer rests neatly below them.

[2] Dynamic HTML is the technique of using JavaScript code to modify the CSS properties of HTML elements on the fly. As this is not a book about JavaScript, we will not delve any deeper into the subject here.

Instead of dealing with the differences between browsers ourselves, we'll leave it to the professionals and use the excellent X script from Cross-Browser.com. Simply download x_core.js and x_event.js from that site and load them into the <head> tag of your page as follows:

<script src="x_core.js" type="text/javascript"></script>
<script src="x_event.js" type="text/javascript"></script>

Now, because the footer may well be covered by the left and right columns when the browser lays them out, we'll want to keep it invisible until we've adjusted the column heights. Make sure the footer <div> has id="footer" set, and add this style rule to the document:

#footer {
  visibility: hidden;
}

Now, when the browser has finished loading the page (and whenever the browser window is resized), we want to find out which of the columns is tallest and resize them all to that height. Then we can display the footer. Because this process may happen repeatedly as the user resizes the browser window, we need to wrap the content of each column in an additional <div>. The structure of the document becomes:

<div id="top">
  <!-- header content -->
</div>
<div id="left">
  <div id="leftcontent">
    <!-- left -->
  </div>
</div>
<div id="center">
  <div id="centercontent">
    <!-- content -->
  </div>
</div>
<div id="right">
  <div id="rightcontent">
    <!-- right -->
  </div>
</div>
<div id="footer">
  <!-- footer -->
</div>

It is these "inner" <div>s that we'll check for the natural height of each column before we set the height of the "outer" <div>s.

Here's the JavaScript function that adjusts the layout using the X library's xHeight and xShow functions, then shows the footer:

<script type="text/javascript">
function adjustLayout()
{
  // Get natural heights
  var cHeight = xHeight("centercontent");
  var lHeight = xHeight("leftcontent");
  var rHeight = xHeight("rightcontent");
  
  // Find the maximum height
  var maxHeight = Math.max(cHeight, Math.max(lHeight, rHeight));
  
  // Assign maximum height to all columns
  xHeight("center", maxHeight);
  xHeight("left", maxHeight);
  xHeight("right", maxHeight);
  
  // Show the footer
  xShow("footer");
}

All that's left is to make this function run when the page is loaded or resized. This is done with xAddEventListener:

function initLayout()
{
  xAddEventListener(window, "resize", adjustLayout, false);
  adjustLayout();
}
xAddEventListener(window, "load", initLayout, false);
</script>

And that does it! The result can be seen in Figure 6-7.

Figure 6-7. Perfected 3 Column Layout with JavaScript

Try out the file 3col-dhtml.html in the code archive to see it in action for yourself!

The only real disadvantage of this method is that it relies on JavaScript. If JavaScript is disabled in the user's browser, none of the adjustments will occur, and the page will display with the three columns of unequal heights and the footer hidden. If that's not acceptable to you, then by all means read on!

6.2.2. Simulating Equal Column Heights with Floats

The layout method I provided in the previous section degraded quite gracefully in the absence of JavaScript, however, the three columns would no longer be of equal height, and the seamless layout would be spoiled. Fortunately, there is a non-JavaScript alternative.

Instead of absolute-positioning all but one of the columns on your page, you can use the float property we saw in Section 6.1 to float the left and right columns against the left and right sides of the page respectively.

#left {
  float: left;
  width: 200px;
}
#right {
  float: right;
  width: 200px;
}

In order to prevent the center column's content wrapping below the side columns, we simply assign it equivalent left and right margins (plus a little inter-column spacing, if desired):

#center {
  margin-left: 210px;
  margin-right: 210px;
  background-color: #ccc;
}

The neat side effect of using float to position the left and right columns is that it permits us to use clear to position content below them. To ensure that any content that follows the three columns is also pushed down, we wrap the columns in a single <div> (with id="wrapper"), then add a fourth, empty <div> (with id="clear") following the three columns. Here's the structure in summary:

<div id="top">
  <!-- header content -->
</div>
<div id="wrapper">
  <div id="left">
    <!-- left content -->
  </div>
  <div id="right">
    <!-- right content -->
  </div>
  <div id="center">
    <!-- center content -->
  </div>
  <div id="clear"></div>
						</div>
<div id="footer">
  <!-- footer -->
</div>

To the empty <div id="clear"> we assign the CSS clear property, which ensures that it appears below the floated columns:

#clear {
  clear: both;
}

This stretches the <div id="wrapper">, ensuring that it encloses all three columns, whatever their lengths. Any content following <div id="wrapper"> will perforce appear below all three columns.

The net result can be seen in Figure 6-8, or you can try it yourself by playing with 3col-float.html in the code archive.

Figure 6-8. Perfected 3 Column Layout with Floats

For the floats to work as intended, though, the three column <div>s must appear in the correct order in the document. As shown in the code above, we must have the left column first, then the right, then the center. This is the main disadvantage of this method: your two side columns (which usually contain secondary content or navigation) must come before the main content of the page.

Not only can this confuse visually impaired visitors using aural browsers (as the secondary content in your side columns is read before the main content in your center column), it also negatively impacts the search engine rank the page is likely to achieve. With the main content appearing later in the code, many search engines will lend less weight to—or even completely ignore—the critical content of the page. Only the method of absolute positioning can truly free you to put your three column blocks in whatever order you like.

The especially eagle-eyed reader will have noticed that, whereas the DHTML solution actually did equalize the heights of the three columns, this method merely makes the footer behave as if the three columns were of equal height. What's the difference? Well when you begin to add borders and backgrounds to the three columns, their actual heights become immediately apparent. As a case in point, note that the gray background of the center column in Figure 6-7 extends down to the footer, whereas in Figure 6-8 it only covers the height of the column's content.

Many intrepid members of the CSS community have pursued solutions to this issue, striving for the look of equal column heights without falling upon the crutch of JavaScript. As of this writing, at least thirty variations upon the two solutions presented here can be found on the Web. The most flexible (in my opinion) has been developed by Petr Stanicek. It wraps additional <div>s around the set of columns to allow each to have a background that extends all the way to the footer. Each of the wrapping <div>s contains an appropriately-aligned, vertically-tiled background (see the background-position and background-repeat properties in Appendix B) that matches the background of one of the columns.

A number of obscure bugs in Internet Explorer for Windows are related to backgrounds and floats, however, so these kinds of layouts can take a lot of tweaking before they'll display correctly in all browsers. If you want a solution that "just works", your best bet is the DHTML solution I presented above.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.22.51.241