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

CSS Technique: 2-col tableless layout

Řešení CSS: Dvousloupcový beztabulkový 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.

Čas od času můžete na své stránce potřebovat dva sloupce stejné výšky. Pokud se výška jejich obsahu liší, jejich pozadí má pokračovat a končit na stejné pozici. Právě takto jsou sloupce tvořeny pomocí tabulek.

Pro vytvoření dvou sloupců v CSS existuje několik způsobů. Můžeme použít plovoucí blok, oba bloky plovoucí, můžeme pozicovat jeden blok do okraje bloku druhého. V každém případě ale blok skončí tam, kde bude končit jeho obsah. Ale to je v pořádku — ve skutečnosti jsou "sloupce stejné výšky" jen pouhou iluzí: nikoli sloupce, ale pozadí pod nimi tvoří požadovaný efekt. Takže nechejme sloupcům jejich výšku a posléze si pohrajme s pozadím. O to tu jde.

1. Pevná šířka

Nejprve vytvořme samotné sloupce. Použijeme např. plovoucí blok. Na stránce bude mateřský blok nazvaný content a v něm budou dva vnořené bloky: sidebar a main. Blok sidebar má být formátován jako levý, užší sloupec a blok main jako sloupec širší vedle něj. Zásadní otázkou je, zda sloupce mají fixní, nebo pružnou šířku. V prvním případě použijeme šírku fixní: levý sloupec má být široký 200 px.

   #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.

Použili jsme zde několik triků:

  1. Je zde použita "Matrjoška", abychom zabránili známým problémům s box-modelem.
  2. Plovoucí blok jsme umístili do okraje (margin) bloku druhého. To je nejsnazší způsob, jak umístit obsah dvou bloků vedle sebe.
  3. Najdeme zde cleaner ("čistič"). Zajišťuje, aby byl mateřský blok ukončen až pod dolní hranou plovoucího bloku.

Máme tedy dva sloupce. Podívejte se na Příklad 1.

Abychom je udělali zdánlivě stejně vysoké, stačí vnějšímu bloku přidat vhodné pozadí. Bude se svisle opakovat a vytvářet po levé straně 200 px široký pruh — a tedy požadovaný tvar sloupců.

   #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%.

Podívejte se na Příklad 2.

2. Pružná šířka

Obdobný postup můžeme použít i pokud má být šířka sloupců pružná, zadaná procentně. Trik spočívá v chytrém umístění obrázku na pozadí. Na tenhle nápad přišel Doug Bowman, publikován byl v jeho článku Liquid Bleach.

Řekněme, že chceme layout rozdělit na sloupce v poměru 30:70. Nejprve proto nastavíme šířku bloku sidebar (stejně jako levý okraj bloku main) na hodnotu 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.

A teď přijde hlavní finta. Musíme udělat dvě věci:

  1. Připravit si obrázek na pozadí ve stejném poměru jako sloupce. Pokud je tedy poměr sloupců např. 30:70, uděláme levý pruh v obrázku 600px široký a pravou část necháme širokou 1400px (obrázek na pozadí by měl být vždy dost široký).
  2. Umístit obrázek na pozadí v témže poměru.
   #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).

To zajistí, že hranice mezi sloupci je vždy (poměrně) ve stejné pozici, když se šířka sloupců bude měnit (jak je znázorněno na obrázku níže). Podívejte se na Příklad 3, kde můžete vidět toto řešení v praxi.


Obr. 1: Umístění pozadí v daném poměru

Můžeme použít i zjednodušenou verzi pozadí a obrázkem podložit jen jeden sloupec (zbytek pozadí bude průhledný) — řešení je ale stále totéž. Úspěšně jsem je testoval ve všech majoritních prohlížečích (WinIE5, WinIE6, Mozilla, Firefox, Opera, Safari).