The 12-Column Grid I Keep, With Named Areas and Container Queries

I rewrote our marketing site grid three times before settling on this: a 12-column CSS Grid with named areas for the hero shape, container queries for the breakpoints, and custom properties for the gutter so designers can change one value.

CSS
Frontend
3 snippets
css-grid
css-variables
code-template
frontend
lucasmoreau

By @lucasmoreau

January 11, 2026

·

Updated May 20, 2026

1,143 views

15

4.4 (13)

/* The grid I drop into every project. One CSS variable controls the gutter,
   the column count is fixed at 12, and minmax(0, 1fr) is the part everyone
   forgets which prevents long words from blowing the layout out. */

.layout {
    --gutter: 24px;
    --max-width: 1200px;

    display: grid;
    grid-template-columns: repeat(12, minmax(0, 1fr));
    gap: var(--gutter);
    max-width: var(--max-width);
    margin-inline: auto;
    padding-inline: var(--gutter);
}

/* Span helpers. The naming matches Bootstrap so designers feel at home. */
.col-span-1  { grid-column: span 1;  }
.col-span-2  { grid-column: span 2;  }
.col-span-3  { grid-column: span 3;  }
.col-span-4  { grid-column: span 4;  }
.col-span-5  { grid-column: span 5;  }
.col-span-6  { grid-column: span 6;  }
.col-span-7  { grid-column: span 7;  }
.col-span-8  { grid-column: span 8;  }
.col-span-9  { grid-column: span 9;  }
.col-span-10 { grid-column: span 10; }
.col-span-11 { grid-column: span 11; }
.col-span-12 { grid-column: span 12; }

/* Start helpers for offset layouts. */
.col-start-2  { grid-column-start: 2;  }
.col-start-3  { grid-column-start: 3;  }
.col-start-4  { grid-column-start: 4;  }
.col-start-7  { grid-column-start: 7;  }

The whole layout fits on a screen because every decision is exposed as a custom property. --gutter is the single value designers ask to change, and threading it through gap, padding-inline, and any nested grid keeps everything aligned. The minmax(0, 1fr) (rather than just 1fr) is the line I always forget at first; without it, a long unbroken word in a child element forces the column wider than its share, which on a 12-column grid means columns 7-12 silently overflow the viewport. Naming columns col-span-N rather than the more recent grid-column: span var(--span) choice was deliberate: designers grep classes faster than they parse arbitrary properties.