Margo Grid

A twelve column grid with named lines, full-bleed support and real subgrid nesting, tuned by four variables.

API

Variables

Four variables tune the whole system, and the fifth is derived from them. Padding and gutters are fully independent — the padding is real padding on the container, the gutters exist only between columns — so any combination is valid, including a padding smaller than the gutter.

variable
--margo-grid-max-widthwidth cap of the content area, before the side padding
--margo-grid-paddingside padding of the container, independent from the gutters
--margo-grid-gutter-xgap between columns
--margo-grid-gutter-ygap between rows
--margo-grid-bleedderived: the distance from the content area to the viewport edge

Containers

utility
margo-gridthe root container: centres, pads, and defines the twelve tracks
margo-grid-subnested grid that reuses the parent tracks through subgrid
margo-grid-flatstandalone twelve columns, no max width and no padding
margo-containersame width and padding as margo-grid, without any column

Columns and rows

utility
margo-col-*a single column by index: margo-col-4 occupies column four
margo-col-start-*start at the beginning of column N
margo-col-end-*end at the end of column N, inclusive
margo-col-span-*span N columns from wherever the item starts
margo-row-*place on row N, spanning one row
margo-row-start-*start on row N, keeping the current end
margo-row-span-*span N rows from wherever the item starts

Full bleed

Bleeding is not a column but a negative margin sized to --margo-grid-bleed, the distance between the content area and the viewport edge. Because it is a margin, it works from any column and at any nesting depth, and the matching padding utility brings the content back onto the grid.

utility
margo-col-fulledge to edge of the viewport, escaping max width and padding
margo-col-contentback to the centred content area, dropping any bleed
margo-col-start-fullbleed off the left edge, keeping the current end line
margo-col-start-contentstart at the content edge, dropping any left bleed
margo-col-end-fullbleed off the right edge, keeping the current start line
margo-col-end-contentend at the content edge, dropping any right bleed
margo-col-span-fullspan the full bleed width regardless of where the item starts
margo-pl-bleedpadding equal to the bleed on the start side
margo-pr-bleedpadding equal to the bleed on the end side
margo-px-bleedpadding equal to the bleed on both sides

Tuning a single grid

These set the grid variables rather than the CSS properties, so they never depend on utility order to win and they cascade into nested grids unless one overrides them again.

utility
margo-gutter-*both gutters, on the spacing scale: margo-gutter-4
margo-gutter-x-*column gap only
margo-gutter-y-*row gap only
margo-padding-*side padding; feeds the bleed, so full-bleed children stay exact

Examples

Usage

A margo-grid centres a twelve column content area, caps it at the maximum width and pads it on both sides. Direct children sit on the whole content area by default, so a plain container is already aligned before you place anything.

tsx
<div className="margo-grid">
  <aside className="margo-col-span-3" />
  <main className="margo-col-start-4 margo-col-end-content" />
</div>

Responsive placement

Every utility takes the standard variants, against the breakpoints the kit declares as numbers — 480, 640, 768, 900, 1080, 1280, 1920 — so a placement can change per breakpoint without leaving the class attribute.

tsx
<div className="margo-col-start-4 900:margo-col-end-10 max-900:margo-col-start-content" />

Details

Named lines

The tracks carry names, which is what makes the utilities readable rather than arithmetic: content-start and content-end bound the content area, and every column exposes a col-start and a col-end.

css
grid-template-columns:
  [content-start] repeat(12, [col-start] minmax(0, 1fr) [col-end]) [content-end];

Rows have no template and no names on purpose: they are addressed by index. A named row line would only be meaningful in a layout whose rows are known in advance, which is not the general case.

Nesting

margo-grid-sub does not create new tracks: it borrows the parent's through subgrid. Grandchildren therefore keep aligning to the same twelve columns at any depth, which a nested grid of its own could only approximate.

tsx
<section className="margo-grid">
  <div className="margo-col-span-8 margo-grid-sub">
    <article className="margo-col-span-4" />
    <article className="margo-col-span-4" />
  </div>
</section>

The nested container must span the columns it wants to inherit. Inside it children are auto-placed, one column each unless they carry a span utility.

Bleeding from anywhere

tsx
<nav className="margo-col-start-full margo-col-end-3 margo-pl-bleed">
  <Item as={Link} to="/margo-ui">
    <Item.Label label="Introduction" />
  </Item>
</nav>