CSS3 & Responsive Design

Multi-Column Layout

20 min Lesson 24 of 60

Introduction to CSS Multi-Column Layout

The CSS Multi-Column Layout module provides a powerful way to flow content across multiple columns, similar to the column-based layouts you see in newspapers, magazines, and academic journals. Before this module existed, creating true multi-column text layouts required complex float-based hacks, JavaScript solutions, or manually splitting content into separate container elements. The Multi-Column Layout module solves this elegantly by letting the browser automatically divide content into columns based on simple CSS properties.

Multi-Column Layout was first proposed as a CSS3 module and has been supported in browsers since the early 2010s. Unlike Flexbox and Grid, which are general-purpose layout systems designed for arranging distinct elements, Multi-Column Layout is specifically designed for flowing continuous content across columns. Think of it as the CSS equivalent of how a word processor or desktop publishing application handles column layouts -- the text flows naturally from one column to the next, filling each column before moving on.

In this lesson, we will explore every aspect of Multi-Column Layout: how to create columns, control their sizing and spacing, add visual dividers between them, manage how content breaks across columns, and understand when Multi-Column Layout is the right tool versus when you should reach for Flexbox or Grid instead.

Creating Columns with column-count

The simplest way to create a multi-column layout is with the column-count property. This property tells the browser exactly how many columns to divide the content into. The browser will calculate the width of each column automatically based on the available space.

Basic column-count Example

.newspaper-article {
    column-count: 3;
}

/* The HTML is just a regular container with text */
<div class="newspaper-article">
    <p>Lorem ipsum dolor sit amet, consectetur adipiscing elit.
    Sed do eiusmod tempor incididunt ut labore et dolore magna
    aliqua. Ut enim ad minim veniam, quis nostrud exercitation
    ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
    <p>Duis aute irure dolor in reprehenderit in voluptate
    velit esse cillum dolore eu fugiat nulla pariatur. Excepteur
    sint occaecat cupidatat non proident, sunt in culpa qui
    officia deserunt mollit anim id est laborum.</p>
</div>

With column-count: 3, the browser divides the container's content area into three equal-width columns. The text flows from the top of the first column to the bottom, then continues at the top of the second column, and so on. The columns are created automatically -- you do not need to wrap your content in separate column elements.

Note: The column-count property only accepts positive integers. Setting it to auto means the number of columns will be determined by other properties (such as column-width). A value of 1 effectively disables multi-column layout.

Setting Column Width with column-width

While column-count specifies an exact number of columns, the column-width property takes a different approach. Instead of dictating how many columns to create, you specify the ideal minimum width for each column. The browser then calculates how many columns will fit in the available space while respecting that minimum width. If the container is wide enough for four columns at the specified width, you get four columns. If the container narrows, the browser reduces the number of columns accordingly.

Using column-width for Responsive Columns

.responsive-text {
    column-width: 250px;
}

/* On a 1000px wide container:
   1000 / 250 = 4 columns, each ~250px wide */

/* On a 600px wide container:
   600 / 250 = 2 columns, each ~300px wide */

/* On a 400px wide container:
   400 / 250 = 1 column, full width */

This behavior makes column-width inherently responsive. As the viewport or container shrinks, columns are removed naturally without requiring media queries. The browser will never make a column narrower than the specified column-width (unless the container itself is narrower than that value). Instead, it reduces the number of columns to maintain readability.

Tip: Use column-width when you want the number of columns to adapt automatically to the available space. Use column-count when you need a specific, fixed number of columns regardless of the container width. In many cases, column-width is the more practical choice because it provides built-in responsiveness.

The columns Shorthand Property

The columns shorthand property lets you set both column-width and column-count in a single declaration. The browser uses whichever constraint produces fewer columns, ensuring that columns are never narrower than the specified width and never more numerous than the specified count.

The columns Shorthand

/* Set both width and count */
.article {
    columns: 200px 3;
    /* Equivalent to:
       column-width: 200px;
       column-count: 3;
    */
}

/* Set only column-count */
.two-columns {
    columns: 2;
    /* Equivalent to:
       column-width: auto;
       column-count: 2;
    */
}

/* Set only column-width */
.flexible-columns {
    columns: 300px;
    /* Equivalent to:
       column-width: 300px;
       column-count: auto;
    */
}

/* Both values together -- browser picks the lesser result */
.constrained {
    columns: 250px 4;
    /* Maximum 4 columns, each at least 250px wide.
       If container is 800px: 800/250 = 3.2, so 3 columns
       (capped at 4, but only 3 fit at 250px minimum) */
}

When you specify both values in the shorthand, the browser creates at most column-count columns, and each column will be at least column-width wide. If the container cannot fit the specified number of columns at the specified minimum width, the browser reduces the column count. This dual-constraint approach gives you fine control over how your columns behave at different container sizes.

Controlling the Gap Between Columns

By default, browsers place a gap between multi-column columns (typically 1em, though the exact default can vary). You can control this gap explicitly using the column-gap property. This is the same column-gap property used in Flexbox and Grid layouts -- it was originally introduced for Multi-Column Layout and later adopted by the other layout modules.

Setting Column Gap

/* Fixed gap in pixels */
.article {
    column-count: 3;
    column-gap: 40px;
}

/* Using em for relative sizing */
.text-content {
    column-count: 2;
    column-gap: 2em;
}

/* Using percentage (relative to container width) */
.responsive-gap {
    column-count: 3;
    column-gap: 5%;
}

/* No gap between columns */
.no-gap {
    column-count: 4;
    column-gap: 0;
}

/* The normal keyword (browser default, usually 1em) */
.default-gap {
    column-count: 3;
    column-gap: normal;
}

Choosing the right gap size is important for readability. Columns that are too close together make it difficult for the reader's eye to track from the bottom of one column to the top of the next. A gap of 20px to 40px (or roughly 1.5em to 2.5em) works well for body text. For narrow columns, a smaller gap may be appropriate; for wide columns with large text, a larger gap improves the visual separation.

Adding Visual Dividers with column-rule

The column-rule property draws a vertical line between columns, acting as a visual separator. It works exactly like the border shorthand and accepts the same values. The column rule is drawn in the center of the column gap, so it does not take up additional space or affect the column widths.

Column Rule Properties

/* Full shorthand: width, style, color */
.article {
    column-count: 3;
    column-gap: 30px;
    column-rule: 1px solid #ccc;
}

/* Individual properties */
.detailed-rule {
    column-count: 3;
    column-gap: 40px;
    column-rule-width: 2px;
    column-rule-style: dashed;
    column-rule-color: #3498db;
}

/* Different rule styles */
.solid-rule    { column-rule-style: solid; }
.dashed-rule   { column-rule-style: dashed; }
.dotted-rule   { column-rule-style: dotted; }
.double-rule   { column-rule-style: double; }
.groove-rule   { column-rule-style: groove; }
.ridge-rule    { column-rule-style: ridge; }
.inset-rule    { column-rule-style: inset; }
.outset-rule   { column-rule-style: outset; }
.none-rule     { column-rule-style: none; }
.hidden-rule   { column-rule-style: hidden; }
Note: The column rule does not occupy any space. It is painted in the middle of the column gap. If the column-gap is set to 0, the rule will still be rendered but will overlap with the column content. Always ensure your column gap is wide enough to accommodate the rule width comfortably.

Practical Rule Styling

Newspaper-Style Layout with Rules

.newspaper {
    column-count: 3;
    column-gap: 30px;
    column-rule: 1px solid #ddd;
    font-family: Georgia, "Times New Roman", serif;
    font-size: 15px;
    line-height: 1.7;
    text-align: justify;
}

.newspaper h2 {
    font-size: 28px;
    margin-bottom: 10px;
    column-span: all;
}

.newspaper p {
    margin-bottom: 12px;
    text-indent: 1.5em;
}

Spanning Columns with column-span

Sometimes you need an element -- typically a heading, a pull quote, or a large image -- to break out of the column flow and stretch across all columns. The column-span property makes this possible. It only accepts two values: none (the default, meaning the element stays within its column) and all (the element spans all columns).

Using column-span for Headings

.multi-col-article {
    column-count: 3;
    column-gap: 30px;
    column-rule: 1px solid #ddd;
}

/* Main heading spans all columns */
.multi-col-article h2 {
    column-span: all;
    text-align: center;
    font-size: 32px;
    margin: 20px 0;
    padding: 15px 0;
    border-top: 2px solid #333;
    border-bottom: 2px solid #333;
}

/* Subheadings also span all columns */
.multi-col-article h3 {
    column-span: all;
    font-size: 22px;
    margin: 15px 0 10px;
    color: #2c3e50;
}

/* Pull quotes span across columns */
.pull-quote {
    column-span: all;
    font-size: 24px;
    font-style: italic;
    text-align: center;
    padding: 20px 40px;
    margin: 20px 0;
    border-left: 4px solid var(--primary);
    background: var(--bg-light);
}

When an element has column-span: all, the multi-column flow is interrupted. The content above the spanning element fills the columns normally. Then the spanning element is rendered across the full width. Then the content below the spanning element begins a new set of columns. This creates natural section breaks within your multi-column content.

Warning: The column-span property only supports none and all. There is no way to span a specific number of columns (like column-span: 2). If you need that level of control, you should consider using CSS Grid instead. Also note that column-span only works on direct children of the multi-column container or elements within the normal flow -- it will not work on floated or absolutely positioned elements.

Controlling Column Breaks

One of the challenges of multi-column layout is controlling where content breaks between columns. You might want to keep a heading together with the paragraph that follows it, prevent a figure from being split across columns, or force a new column to start at a specific point. CSS provides several properties to handle column breaks, which parallel the page break properties used in print stylesheets.

break-inside

The break-inside property controls whether a break should occur inside an element. The most common use is preventing elements from being split across columns.

Preventing Breaks Inside Elements

/* Prevent cards from splitting across columns */
.card {
    break-inside: avoid;
    margin-bottom: 15px;
    padding: 15px;
    border: 1px solid #ddd;
    border-radius: 8px;
}

/* Prevent figures from splitting */
figure {
    break-inside: avoid;
}

/* Prevent blockquotes from splitting */
blockquote {
    break-inside: avoid;
}

/* Values for break-inside */
.auto-break    { break-inside: auto; }    /* Default behavior */
.avoid-break   { break-inside: avoid; }   /* Avoid breaks */
.avoid-column  { break-inside: avoid-column; } /* Avoid column breaks specifically */
.avoid-page    { break-inside: avoid-page; }   /* Avoid page breaks (for print) */

break-before and break-after

These properties control whether a break should occur before or after an element. You can force a new column to start before a specific element, or ensure content after an element begins in a new column.

Forcing and Preventing Column Breaks

/* Force a new column before every h3 */
.multi-col h3 {
    break-before: column;
}

/* Force a new column after a separator element */
.column-separator {
    break-after: column;
}

/* Prevent a break immediately after a heading */
.multi-col h2,
.multi-col h3,
.multi-col h4 {
    break-after: avoid;
}

/* Values for break-before and break-after */
.auto          { break-before: auto; }        /* Default */
.avoid         { break-before: avoid; }       /* Avoid any break */
.column-break  { break-before: column; }      /* Force a column break */
.avoid-column  { break-before: avoid-column; } /* Avoid column break */
.page-break    { break-before: page; }        /* Force a page break (print) */
Tip: Always set break-after: avoid on headings within multi-column layouts. There is nothing worse visually than a heading sitting alone at the bottom of a column with its related content starting at the top of the next column. This is sometimes called a "widow heading" and it confuses readers.

Widows and Orphans

The widows and orphans properties come from print typography and control how many lines of a paragraph must appear at the top or bottom of a column (or page). An orphan is a line left behind at the bottom of a column when the rest of the paragraph continues in the next column. A widow is a lone line at the top of a column that belongs to a paragraph that started in the previous column.

Controlling Widows and Orphans

.multi-col-text {
    column-count: 3;
    column-gap: 30px;

    /* At least 3 lines must remain at the bottom of a column */
    orphans: 3;

    /* At least 3 lines must appear at the top of a new column */
    widows: 3;
}

/* Default values are typically 2 for both */
.default-typography {
    orphans: 2;
    widows: 2;
}

Setting higher values for widows and orphans improves the visual quality of multi-column text. However, be aware that the browser may not always be able to honor these values -- if the paragraph is very short, the browser has limited options for how to distribute the lines. The widows and orphans properties are hints to the layout engine, not absolute demands.

Column Fill: Auto vs Balance

The column-fill property controls how content is distributed across columns. By default, browsers try to balance the content so that all columns are approximately the same height. You can change this behavior to make content fill columns sequentially.

Column Fill Options

/* Balance: all columns are approximately equal height (default) */
.balanced {
    column-count: 3;
    column-fill: balance;
    /* Content is distributed so columns are roughly equal.
       The last column may be slightly shorter. */
}

/* Balance-all: balance across all column boxes (fragmented contexts) */
.balance-all {
    column-count: 3;
    column-fill: balance-all;
}

/* Auto: fill columns sequentially */
.sequential {
    column-count: 3;
    column-fill: auto;
    height: 400px;
    /* Content fills the first column completely,
       then the second, then the third.
       The last column may be partially filled or empty. */
}
Warning: The column-fill: auto value only has a visible effect when the multi-column container has a fixed height (or max-height). Without a fixed height, the container will expand to fit all content, and the browser will balance the columns regardless of the column-fill value. If you want columns to fill sequentially, you must constrain the container's height.

Practical Example: Sequential Fill with Fixed Height

.fixed-height-columns {
    column-count: 3;
    column-fill: auto;
    height: 300px;
    overflow: hidden;
    column-gap: 25px;
    column-rule: 1px solid #e0e0e0;
}

/* Compare with balanced (no fixed height needed) */
.balanced-columns {
    column-count: 3;
    column-fill: balance;
    column-gap: 25px;
    column-rule: 1px solid #e0e0e0;
    /* Columns will be roughly equal height */
}

Responsive Multi-Column Layout

One of the strengths of Multi-Column Layout is how well it works with responsive design. There are several strategies for making your multi-column layouts adapt to different screen sizes.

Strategy 1: Use column-width for Automatic Responsiveness

Automatic Column Reduction

/* The browser automatically reduces columns as the viewport shrinks */
.auto-responsive {
    column-width: 280px;
    column-gap: 30px;
    column-rule: 1px solid #ddd;
}

/* On wide screens: 3-4 columns
   On tablets: 2 columns
   On phones: 1 column
   No media queries needed! */

Strategy 2: Media Queries with column-count

Explicit Column Changes at Breakpoints

.article-text {
    column-gap: 30px;
    column-rule: 1px solid #ddd;
}

/* Desktop: 3 columns */
@media (min-width: 1024px) {
    .article-text {
        column-count: 3;
    }
}

/* Tablet: 2 columns */
@media (min-width: 600px) and (max-width: 1023px) {
    .article-text {
        column-count: 2;
    }
}

/* Mobile: 1 column (default) */
@media (max-width: 599px) {
    .article-text {
        column-count: 1;
    }
}

Strategy 3: Combining Both Approaches

Shorthand with Media Query Overrides

.content {
    columns: 250px 3;
    column-gap: 25px;
    column-rule: 1px solid #eee;
}

/* On very small screens, force single column */
@media (max-width: 500px) {
    .content {
        columns: 1;
        column-rule: none;
    }
}

When to Use Multi-Column Layout vs Flexbox vs Grid

Understanding when to use Multi-Column Layout versus Flexbox or Grid is crucial for writing effective CSS. Each layout system has different strengths and was designed for different purposes.

Use Multi-Column Layout When:

You have continuous flowing text content that should be distributed across columns, like a newspaper article, a long list of items, or a terms-and-conditions page. Multi-Column Layout handles text reflow and column balancing automatically. It is the only layout system that can split a single paragraph across multiple columns.

Use Flexbox When:

You have a set of distinct items that need to be arranged in one direction (a row or a column). Navigation bars, card layouts in a single row, centering content, and distributing space between items are all natural fits for Flexbox. Flexbox items are independent elements, not flowing text.

Use CSS Grid When:

You need a two-dimensional layout with explicit control over rows and columns. Grid is ideal for page layouts, image galleries, dashboards, and any design where elements need to be placed at specific grid intersections. Grid gives you precise control over the placement of each item.

Comparison: Same Content, Different Approaches

/* Multi-Column: flowing text across columns */
.text-columns {
    column-count: 3;
    column-gap: 20px;
}

/* Flexbox: distinct items in a row */
.flex-items {
    display: flex;
    gap: 20px;
}
.flex-items > * {
    flex: 1;
}

/* Grid: items placed in a 2D grid */
.grid-items {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
}
Note: Multi-Column Layout is sometimes combined with Flexbox or Grid. For example, you might use Grid for the overall page layout, and then apply column-count to a specific content area within one of the grid cells. These layout systems are complementary, not mutually exclusive.

Practical Examples

Example 1: Magazine-Style Article

Full Magazine Layout

<article class="magazine-article">
    <h1>The Future of Web Design</h1>
    <p class="lead">An in-depth look at emerging trends...</p>
    <p>Body text that flows across multiple columns...</p>
    <h2>Section Heading</h2>
    <p>More content that continues across columns...</p>
    <blockquote class="pull-quote">
        "Design is not just what it looks like. Design is how it works."
    </blockquote>
    <p>Additional paragraphs of content...</p>
</article>

CSS for Magazine Layout

.magazine-article {
    columns: 280px 3;
    column-gap: 35px;
    column-rule: 1px solid #e0e0e0;
    font-family: Georgia, serif;
    font-size: 16px;
    line-height: 1.75;
    text-align: justify;
    orphans: 3;
    widows: 3;
}

.magazine-article h1 {
    column-span: all;
    font-size: 42px;
    text-align: center;
    margin-bottom: 5px;
    font-family: "Playfair Display", serif;
}

.magazine-article .lead {
    column-span: all;
    font-size: 20px;
    font-style: italic;
    text-align: center;
    color: #666;
    margin-bottom: 25px;
    padding-bottom: 25px;
    border-bottom: 2px solid #333;
}

.magazine-article h2 {
    column-span: all;
    font-size: 26px;
    margin: 25px 0 15px;
    padding-top: 15px;
    border-top: 1px solid #ddd;
}

.magazine-article .pull-quote {
    column-span: all;
    font-size: 22px;
    font-style: italic;
    text-align: center;
    padding: 20px 50px;
    margin: 20px 0;
    background: #f8f9fa;
    border-left: 4px solid var(--primary);
    break-inside: avoid;
}

.magazine-article p {
    margin-bottom: 12px;
    text-indent: 1.5em;
}

.magazine-article p:first-of-type {
    text-indent: 0;
}

.magazine-article p:first-of-type::first-letter {
    font-size: 3.5em;
    float: left;
    line-height: 1;
    margin-right: 8px;
    font-family: "Playfair Display", serif;
    color: var(--primary);
}

@media (max-width: 600px) {
    .magazine-article {
        columns: 1;
        column-rule: none;
        text-align: left;
    }
}

Example 2: Multi-Column Card List

Card List That Flows Across Columns

<div class="card-list">
    <div class="card">
        <h3>Card Title 1</h3>
        <p>Card description text...</p>
    </div>
    <div class="card">
        <h3>Card Title 2</h3>
        <p>Card description text...</p>
    </div>
    <!-- More cards... -->
</div>

CSS for Card List

.card-list {
    column-count: 3;
    column-gap: 20px;
}

.card {
    break-inside: avoid;
    margin-bottom: 20px;
    padding: 20px;
    background: var(--bg-white);
    border: 1px solid var(--border-light);
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}

.card h3 {
    margin-bottom: 8px;
    color: var(--text-dark);
}

.card p {
    color: var(--text-light);
    line-height: 1.6;
}

@media (max-width: 900px) {
    .card-list { column-count: 2; }
}

@media (max-width: 500px) {
    .card-list { column-count: 1; }
}

Example 3: Multi-Column Footer Links

Footer Navigation Using Multi-Column

.footer-links {
    column-count: 4;
    column-gap: 20px;
}

.footer-links li {
    break-inside: avoid;
    padding: 4px 0;
}

.footer-links a {
    color: #bbb;
    text-decoration: none;
    transition: color 0.2s;
}

.footer-links a:hover {
    color: #fff;
}

@media (max-width: 768px) {
    .footer-links {
        column-count: 2;
    }
}

@media (max-width: 480px) {
    .footer-links {
        column-count: 1;
    }
}

Common Pitfalls and Best Practices

Pitfall 1: Images Breaking Across Columns

Images and other replaced elements can be split across columns, which looks broken. Always use break-inside: avoid on image containers and figures within multi-column layouts.

Preventing Image Breaks

.multi-col img {
    max-width: 100%;
    height: auto;
}

.multi-col figure {
    break-inside: avoid;
    margin: 0 0 15px;
}

.multi-col .media-block {
    break-inside: avoid;
    display: inline-block;
    width: 100%;
}

Pitfall 2: Tall Elements Overflowing Columns

If a single element is taller than the column height (when the container has a fixed height), it will overflow. Plan your content so that individual elements are not excessively tall, or avoid setting a fixed height on the multi-column container.

Pitfall 3: Inconsistent Browser Handling of Breaks

Different browsers may handle column breaks slightly differently, especially for edge cases. Test your multi-column layouts across browsers, particularly when using break-inside: avoid on many elements, as this can lead to unexpected column height differences.

Tip: For the best multi-column reading experience, keep your line length between 45 and 75 characters per line. This is the generally accepted range for optimal readability. If your columns are too narrow or too wide, readers will struggle. Use column-width with a value around 250px to 350px for body text at standard font sizes to stay within this range.

Browser Support and Vendor Prefixes

Multi-Column Layout has excellent browser support in all modern browsers. However, some older browsers may require vendor prefixes. In modern development, vendor prefixes are generally unnecessary for multi-column properties, but if you need to support very old browsers, you can include them as a fallback.

Prefixed Fallbacks (For Legacy Support)

.legacy-support {
    -webkit-column-count: 3;
    -moz-column-count: 3;
    column-count: 3;

    -webkit-column-gap: 30px;
    -moz-column-gap: 30px;
    column-gap: 30px;

    -webkit-column-rule: 1px solid #ddd;
    -moz-column-rule: 1px solid #ddd;
    column-rule: 1px solid #ddd;
}
Exercise 1: Create a newspaper-style article layout with three columns. Add a main heading that spans all columns, a drop cap on the first paragraph, column rules between columns, and at least one pull quote that also spans all columns. Set appropriate orphans and widows values. Make the layout responsive so it becomes two columns on tablets and one column on mobile devices.
Exercise 2: Build a "masonry-style" card layout using Multi-Column Layout. Create at least 8 cards with varying amounts of content. Ensure no card breaks across columns using break-inside: avoid. Add column rules and use the columns shorthand to set both a minimum width and maximum count. Test that columns reduce properly as the viewport narrows.
Exercise 3: Create a comparison between Multi-Column Layout and CSS Grid for the same content. First, build a terms-and-conditions page using Multi-Column Layout with flowing text. Then, build a product feature grid using CSS Grid for distinct items. Finally, combine both in a single page where the overall layout uses Grid, but the text content area within uses Multi-Column Layout. Document in comments why each approach was chosen for each section.

Summary

CSS Multi-Column Layout provides an elegant solution for flowing content across multiple columns, bringing newspaper and magazine-style layouts to the web with minimal CSS. The column-count property sets a fixed number of columns, column-width creates responsive columns that adapt to the available space, and the columns shorthand combines both constraints. You can style column gaps with column-gap and add visual dividers with column-rule. The column-span: all property lets headings and other elements stretch across all columns, while break-inside, break-before, and break-after give you control over where content splits between columns. The column-fill property determines whether columns are balanced or filled sequentially. Multi-Column Layout is best used for continuous text content; for arranging distinct items, Flexbox and CSS Grid are more appropriate tools. By understanding each layout system's strengths, you can choose the right tool for every design challenge.