English-only | Jenom česky | Bilingual/Dvojjazyčně

CSS Technique: 2-col tableless layout

Sometimes you may need two columns of the same height in your layout. If the height of their content differs, their backgrounds should flow and end at the same position. This is exactly how columns were made by tables.

There are several ways to make two columns in CSS. You can use one floating block, both blocks floating, one block positioned into other's margin etc. Anyway, every time the block ends where its content ends. That's OK — in fact, the "same-height columns" is just a design illusion: not the columns, but the background under them makes the effect. Thus, let's make the columns of their own height and then just play with the background. That's the matter.

1. Fixed width

First, we make the columns themselves. I. e. we'll use the floating block. There will be parent block named content containg two child-blocks: sidebar and main. The sidebar should be formatted as left (narrower) column, the main should be placed next to it, wider. The essential problem is if the columns use fixed, or fluid width. In the first example, we'll use the fixed width: the left column has to be 200 px wide.

   #content {
      width: 90%;
      margin:1em auto;
      border: 1px solid black;
      text-align:left;
      max-width: 1024px;
      }
   #sidebar {
      float: left;
      width: 200px;
      margin:0; padding:0;
      }
   #sidebar-content {
      margin:0; padding: 0.5em 1em;
      font-size: 70%;
      }
   #main {
      margin:0 0 0 200px; padding:0;
      }
   #main-content {
      margin:0; padding: 0.5em 1em;
      font-size: 100%;
      }
   hr.cleaner {
      clear:both;
      height:1px;
      margin: -1px 0 0 0; padding:0;
      border:none;
      visibility: hidden;
      }
...

   <div id="content">
   
   <div id="sidebar"><div id="sidebar-content">
   Left column content...
   </div></div>
   
   <div id="main"><div id="main-content">
   Right column content...
   </div></div>
   
   <hr class="cleaner" />
   
   </div>

We used several tricks here:

  1. The "Matryoshka" hack is used (sorry, not translated yet, see the example at least) to avoid the well known box model problem.
  2. We put the floating block in the margin of the second block. This is the simplest way to keep contents of two block next to each other.
  3. The cleaner can be found here. It makes the parent block to be completed bellow the floater bottom edge.

So, we've got two columns. See the Example 1.

To make their height seemingly the same, just add suitable background to the covering block content. It will be repeated vertically, making 200px wide stripe on the left side — this is the desired shape of the columns.

   #content {
      ...
      background: url('bkgr200.gif') top left repeat-y;
      ...
      }

See the Example 2.

2. Fluid width

Similar technique can be used even if the width of the columns has to be propotional (by percentage). The trick is made by smart positioning of the background. The idea comes from Doug Bowman, published in his Liquid Bleach article.

Let's say, we want the layout to be divided into columns in the 30:70 ratio. Thus, we set the width of sidebar (as well as the main's left margin) to 30%.

   ...
   #sidebar {
      ...
      width: 30%;
      ...
      }
   #main {
      ...
      margin:0 0 0 30%;
      ...

Now comes the tricky part. We have to do two things:

  1. Prepare the background image in the same ratio as the columns. I. e., if the ratio is 30:70, we make the left stripe in the image 600px wide and the right part 1400px wide (the background image should be wide enough).
  2. Position the image in the background in the same ratio as well.
   #content {
      ...
      background: url('bkgr.gif') 30% 0% repeat-y;
      ...
      }

This makes the column division line always in the proper position when the column width changes, as illustrated bellow. See the Example 3 to see this solution in action.



Fig. 1: Positioning the background in the ratio

We can also use simplified version of the background and underlay only one column (the rest of the background will be transparent), but the solution stays the same. I tested it successfully in all major browsers (WinIE5, WinIE6, Mozilla, Firefox, Opera, Safari).