Multi-column layout in CSS

To flow content into several columns, two new CSS properties are proposed., columns and column-rule.

The formatting model of CSS1 is changed to include the new properties. Elements can now specify that their content, including child elements, should be flowed into columns. That means that the width of those child elements is derived from the column width instead of the parent's full width.

By default, i.e., when there is only one column, the sum of margin, border, padding and width for any block element is still equal to the width of the parent element. But when there are more columns, the sum is equal to the column width.

| <---------------------- width ----------------------> |
|                                                       |
|                                                       |
|                         | * |                         |
|                         | * |                         |
|  #####################  | * |  # |               | #  |
|  # .---------------. #  | * |  # |               | #  |
|  # |               | #  | * |  # |               | #  |
|  # |               | #  | * |  # |               | #  |
|  # |               | #  | * |  # |               | #  |
|  # |               | #  | * |  # |               | #  |
|  # |               | #  | * |  # `---------------' #  |
|  # |               | #  | * |  #####################  |
|  # |               | #  | * |                         |
|  # |<child's width>|    | * |                         |
|  #                      | * |                         |
|   ^-- child's padding     ^-- column rule             |
   ^-- child's border
  ^-- child's margin       ^-^-- 2 x 1/2 gutter

One can either specify the number of columns or the desired width of a column. All columns have the same width. The gutters and optional vertical rules between the columns can also be given. If the number of columns is specified, the actual column width is found by dividing the element's width by it. To be precise (n = number of columns, w = actual column width):

width = n * w + (n - 1) * (gutter + column-rule)       (1)

If the desired column width is specified instead, the number of columns is found by dividing the width by the desired column width and rounding to the nearest integer (w' = desired column width):

width = n' * w' + (n' - 1) * (gutter + column-rule)    (2)
n = round(n')                                          (3)

The actual width can thus be different from the desired width. For example: if the width of the element is 50em and the desired column width is 10em, with a 2em gutter and no rules, there is room for 4.3 columns (by equation 2), which rounds to 4 (by equation 3). The actual column width then works out to be 11em (by equation 1), or just a little larger than the desired width.

The formatter should try to divide the contents over the columns in such a way that all columns are of equal height (balanced columns).

'columns'

Value: [ <length> | <number> ] [ <length> | <percentage> ]?
Initial: 1
Applies to: block-level elements
Inherited: no
Percentage values: relative to element's width

The first part of the columns property sets the ideal column width of an element. If the column width is a length value, the number of columns will increase as the canvas is enlarged:

  DIV { columns: 20em }   /* relative to the font size */

To indicate a fixed number of columns, a number can be used:

  BODY { columns: 4 }    /* 4 columns */

All values, length or number, should only be used to determine the number of columns. Once found, the available space should be split into columns with equal widths and the same space between them.

The space between the columns (called gutter), can optionally be specified by putting a second value on the columns property. The default is UA dependent. If a percentage is given, it is relative to the element's width.

If there is a rule between columns (see 'column-rule' below), half of the gutter is at each side of the rule.

The gutter is transparent, which means the parent's background shines through.

'column-rule'

Value: <width> <height>? || <style> || <url> || <color>
Initial: medium 100% none
Applies to: all block elements
Inherited: no [[yes?]]
Percentage values: relative to own width and height, respectively.

If the style of the rule is not 'none', the gutter is split in two halves and the rule is put in between.

<width>
The width (thickness) of the rule can be: [ thin | medium | thick | <length> | <percentage> ]. Thin, medium and thick are the same widths as for the border property. If the value is a percentage, it is relative to the element's width. Initial value is 'medium'.
<height>
If there is a second length value, it represents the height of the rule. A percentage refers to the element's height. Initial value is 100%.
<style>
The style is a keyword from: [ none | dotted | dashed | solid | double | groove | ridge | inset | outset ]. If no value is specified, 'none' is assumed. See the 'border' property for the meaning of each keyword.
<url>
A URL for an image that is tiled to cover the rule. If a URL is specified and it can be loaded, the <style> is ignored.
<color>
The color of the rule. If omitted the value is UA dependent. The color is used

Possible enhancements

If the height of an element is known beforehand and (because the 'height' property is not 'auto' or the formatter is working within a fixed frame height), it should be possible to specify that the columns should not be balanced. This could be done, e.g., by adding a keyword 'unbalanced' to the 'columns' property.

What happens if the height is specified but is too small? CSS1 says that the element gets a (vertical) scroll bar. Another option is to add extra columns and a horizontal scrollbar instead. Maybe this latter option should be indicated on the 'columns' property as well, e.g., by adding the keyword 'fixed-height'.

'Fixed-height' and 'unbalanced' could actually be combined into a single keyword, applying both to the case that the specified height is too large and too small.

Instead of adding a keyword 'unbalanced' or 'fixed-height' to 'columns' to change the meaning of 'height', one could also add a new property 'column-height', which is 'auto' by default, but implies unbalanced columns and/or a horizontal scrollbar when set to any other value.

A child element of an element with columns might be allowed to span several columns. A property 'column-span' could be added for that purpose. An element cannot span more columns than are available to its right.

New properties are needed to control breaking text between columns, e.g., to force a header to start in a new column.

Maybe a way to specify a minimum and maximum width for the columns is needed as well, with a way to say where the remaining unused space is put.

Formatting example

<STYLE>
  DIV  { 
    columns: 20em 3em;
    width: auto;
  }
  H1 { columns: 1 }
</STYLE>

<BODY>
  <H1>THIS IS THE HEADLINE WHICH IS QUITE LONG</H1>
  <DIV>
  <P>This is the first paragraph. The first paragraph comes
      first, before the second.
  <P>After the first paragraph comes the second paragraph
      which you are reading now.
  <P>The third paragraph is the last paragraph. Not much
      more to say about that.
  </DIV>
</BODY>

Since the value of 'columns' is specified in a length unit, the number of columns will depend on the available width, i.e., the width of the BODY element. A User Agent may use two columns when started:

  THIS IS THE HEADLINE WHICH GOES ON TOP

  This is the first     graph which you 
  paragraph. The        are reading now.
  first paragraph       
  comes first, be-      The third para-
  fore the second.      graph is the last
                        paragraph. Not 
  After the first       much more to say
  paragraph comes       about that.
  the second para-      

If the canvas is enlarged, three columns may be used instead:

  THIS IS THE HEADLINE WHICH IS QUITE LONG

  This is the first     After the first       The third para-
  paragraph. The        paragraph comes       graph is the last
  first paragraph       the second para-      paragraph. Not
  comes first, before   graph which you       much more to say
  the second.           are reading now.      about that.

Margin, border and padding values should be honored within the columns. If the columns are not wide enough to display content properly, the UA may decide to reduce the number of columns.


Dave Raggett
Håkon W Lie
Bert Bos


Updated: 960702, 960704