Multicolumn layout allows text and elements to flow from one column to another automatically. With it, we can create text layouts that mimic those found in newspapers, magazines and ebooks. We can also use it to create space-efficient user interfaces.
1. Defining Column Number and Width Using columns
To create multiple columns, set the columns property:
<div style=”columns: 2″>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing … </p>
<p>Duis aute irure dolor in reprehenderit in voluptate … </p>
</div>
The columns property is a shorthand property for column-width and column-count . With columns , the first value that can be interpreted as a length becomes the value of column- width . The first value that can be interpreted as an integer becomes the value of column- count . Order doesn’t matter. A declaration such as columns: idem 3 is the shorthand way of typing column-width: 10em; column-count: 3 . It’s also equivalent to typing columns: 3 10em .
If a value is unspecified, its initial value is auto . In other words, columns: 4 has the same effect as typing columns: 4 auto or column-width: auto; column-count: 4 .
Setting column-width determines the optimal size for each column. Its value should be in length units—such as column-width: 200px or column-width: 10em . Percentages won’t work.
“Optimal”, of course, means that column-width sets the ideal width. The actual width of a column may be wider or narrower than the value of column-width . It depends on the available space and/or viewport size.
In the example pictured below, for example, the container is 800px wide and the column- width value is 15em . That gives us three columns.
But if we expand the width of the container to 1920 pixels, there’s now room for six columns:
Shrinking the width of the container to 450 pixels, on the other hand, reduces this layout to a single column.
Setting the column-count property defines the optimal number of columns to create. Its value must be an integer greater than 0 .
When column-width is something other than auto , the browser creates columns of that width up to the number of columns specified by column-count. If column-width is auto , the browser will create the number of columns specified by column-count. That may be more easily shown than explained, so let’s illustrate it.
In the images that follow, our container has a column-count value of 3 , and a column-width value of auto . Whether our container is 800 pixels wide (as in the first image) or 450 pixels wide (as in the second image), we still have three columns.
Now compare these to the following two images. In both cases, our container has a coLumn- count value of 3 , and a column-width value of 10em . When the container is 800 pixels wide, the number of columns remains the same, as shown below.
But when our container is 400 pixels wide, we can only fit two columns, as shown below.
This goes out of the window entirely if we set the height of a column container. Setting a fixed height on a container forces the browser to create additional columns to accommodate the container’s content. In this case, the column-count property is ignored.
2. Spacing Columns with column-gap and column-rule
The number of columns that can fit in a container also depends on the value of coLumn-gap . Known as the gutter in print design, the column gap sets the distance between each column. The initial value of coLumn-gap is normal . In most browsers, that’s 1em or 16px .
Increasing or decreasing the width of the coLumn-gap can affect both the width of each column and the space between. For example, if a container is 45em wide with column-width: 15em and column-gap: normal applied, its contents will be divided into two columns rather than three, as shown below.
Changing coLumn-gap to 0 , however, gives us our full three-column layout, as shown below.
Without a coLumn-gap , there’s now sufficient space for three columns.
As with column-width , the value of coLumn-gap should be either 0 or a positive length value.
Negative lengths such as -2em are invalid.
Although originally defined as part of the multicolumn specification, newer browsers (Firefox 63 and later, Chrome and Edge 84 and later, and Safari 14.2 and later) also support the use of column-gap with Grid and Flexbox. Similarly, you can use the gap shorthand property—which was first defined by the CSS Grid specification—with multicolumn and Flexbox layouts.
With column-rule , we can add lines to visually separate columns. It functions similarly to border , and accepts the same values. For example:
.multi-col {
column-rule: 5px hsl( 190, 73%, 50% ) dashed;
}
Like border , column-rule is a shorthand for the column-rule-width , column-rule-style , and column-rule-color properties. Each column-rule-* property accepts the same values as its border counterpart. An example of using column-rule is shown below.
Column width isn’t affected by changes to column-rule . Instead, column rules sit at the midpoint of the column gap. If the width of the rule exceeds that of the gap, the column rule renders beneath the columns’ contents.
3. Images within Columns
In cases when an image is wider than its column, the text gets rendered on top of the image.
This is the expected behavior that’s defined by the specification.
The image below shows an image within a column sitting at the bottom of the stacking context in Firefox.
Adding a width: 100% declaration to the image or object constrains the image width to that of the column box, as shown below. It also constrains the height based on the aspect ratio of the image. You can add height: auto to ensure this behavior.
Floated elements within a multicolumn layout are floated within the column box. In the image below, the <img> element has a float: inline-start rule applied. Text still flows around the image, but within the constraints of the column.
Multicolumn layout doesn’t automatically create a new stacking context. Positioned elements in a multicolumn container are positioned relative to the root stacking context unless you create a local stacking context on the container.
4. Making Elements Span Columns
We can also make a particular element span columns with the column-span property. This property accepts two values: none and all . Using none means that the element will be part of the normal column flow, while using all will make the element span every column.
It’s not currently possible to make an element span a particular number of columns. We’re limited to specifying whether it should span all columns or none at all. Consider the layout shown below, which shows how an <h1> element fits into the multicolumn layout flow.
Corgi photo by Alvan Nee from Unsplash.
Here, the <h1> element (the article headline “Dog bites man …”) is part of the multicolumn layout flow. It sits within a column box, wrapping as appropriate. Now let’s add column-span: all :
article > hi {
column-span: all;
}
This gives us the layout shown below, with a headline that spans all of our columns. [1]
5. Managing Column Breaks within Elements
In a multicolumn layout, a long block of text may start in one column and end in another, as illustrated below.
To prevent this, use break-inside: avoid or break-inside: avoid-coLumn . The break- inside property applies to the children of a multicolumn container. For example, to prevent all children of .multi-col from breaking across column boxes, use the following:
.multi-col > * {
break-inside: avoid-column;
}
Now the purple paragraph no longer breaks across columns, as can be seen below.
The break-inside property also affects paged media, which explains why there are both avoid and avoid-coLumn values. The difference? The avoid-coLumn property only prevents a box from breaking across columns, while avoid prevents a box from breaking across both columns and pages.
It’s also possible to force a break before or after an element using break-before and break- after . Let’s force a column break before the third paragraph:
.multi-col p:nth-of-type(3){
background-color: #c09a;
break-before: column;
}
Here, we’ve used the column value to force a column break before the selected element, as illustrated below.
The break-after property works similarly, forcing a column break after the selected element. Using break-before: always also forces column breaks. However, the always value also applies to paged media, where column only applies to multicolumn layout.
Basic browser support for multicolumn layout is quite good. Support for break-before , break-after , and break-inside , however, is a different story.
Safari (versions 14.2 and later), Chrome, and Edge support the column and avoid-column values for break-before and break-after , but lack support for the always value. Instead, you can use the -webkit-column-break-before and -webkit-column-break-after properties with always . These prefixed properties are remnants of an earlier version of the multicolumn specification, but they function in much the same way as break-before and break-after . If you use the -webkit-column-* properties, future-proof your CSS by including the standardized properties.
Firefox, on the other hand, only supports the always value of break-before and break- after , and only for printed documents. Firefox also lacks support for the avoid-column value of break-inside . As a workaround, you can use the avoid value, since break-inside: avoid works for columns and pages in every browser.
6. Optimizing the User Interface
Arranging paragraphs of text isn’t the only use case for multicolumn layouts. We can also use them with lists to optimize the use of horizontal space. Consider the layout shown below, representing a list split into three columns.
Your first thought might be to split this list into three separate lists and use floats, Flexbox or Grid to place them side by side. Here’s what that markup might look like:
<div class=”grid-3-across”>
<ul>
<li>Apples</li>
<li>Oranges</li>
<li>Bananas</li>
<li>Dragon fruit</li>
</ul>
<ul>
<li>Cherries</li>
<li>Strawberries</li>
<li>Blueberries</li>
<li>Raspberries</li>
</ul>
<ul>
<li>Durian</li>
<li>Mangosteen</li>
<li>Mangoes</li>
</ul>
</div>
And the accompanying CSS:
.grid-3-across {
display: grid;
grid-template-columns: repeat(3, 1fr);
}
While this approach works, it requires slightly more markup than a single list element. We’re using three <uL> elements instead of one. With a multicolumn layout, we can use a single element:
<ul style=”columns: 3″>
<li>Apples</li>
<li>Oranges</li>
<li>Bananas</li>
<li>Dragon fruit</li>
<li>Cherries</li>
<li>Strawberries</li>
<li>Blueberries</li>
<li>Raspberries</li>
<li>Durian</li>
<li>Mangosteen</li>
<li>Mangoes</li>
</ul>
What’s more, multicolumn layout automatically balances the number of items in each column.
If our list grows to 16 or 18 items, we don’t have to edit the markup to rebalance the list.
Another use case for multicolumn layouts is wrangling lists of checkbox inputs. Here, too, we can maximize the use of horizontal space to create more compact forms, as pictured below.
Use multicolumn layout when you have blocks of content to be automatically distributed and evenly spaced across several columns. It isn’t well suited to creating page layouts—such as adding a navigation column and a main content column. For page layouts, CSS Grid is a better choice. We’ll discuss Grid later in the chapter.
Source: Brown Tiffany B (2021), CSS , SitePoint; 3rd edition.