Grid & Container

Which grid

Sulphuris ships two. .grid + .col-* is the default โ€” flexbox, twelve columns, responsive widths, offsets and gutters. Use it for page layout and anything column-shaped.

Reach for native CSS grid (.d-grid + .grid-cols-* + .gap-*) when you need two-dimensional control: equal-height rows, row templates, item spanning.

They compose โ€” a .col-6 can be a .d-grid.

Container

.container centers content with max-width: 105rem (1680px at the default root โ€” the same width as the xxl breakpoint, which is why the two convert together) and horizontal padding that switches at the lg breakpoint:

Viewport Padding (each side)
below lg 1rem (16px)
lg and up 3.5rem (56px)
<div class="container">โ€ฆ</div>

Grid row

.grid is a display: flex; flex-flow: row wrap wrapper. It has no gutter by itself.

Add .grid-gutter to apply negative side margins that cancel the column padding, producing consistent gutters between columns without extra math on the outside edges:

Viewport Column padding (each side) Row negative margin (each side)
below lg 0.5rem (8px) -0.5rem
lg and up 1rem (16px) -1rem

The full gutter values are $grid-gutter-mobile: 16px and $grid-gutter: 32px โ€” each side gets half. The halving happens in px and only the finished value converts to rem, so the row's negative margin and the column's padding can never round to different units.

.grid-gutter and .container can be combined on the same element. When combined, the padding accounts for both the container offset and the half-gutter:

<div class="grid grid-gutter container">
  <div class="col-12 col-md-6 col-lg-4">โ€ฆ</div>
  <div class="col-12 col-md-6 col-lg-4">โ€ฆ</div>
  <div class="col-12 col-md-6 col-lg-4">โ€ฆ</div>
</div>

Columns โ€” .col-N

12 columns. Width is a percentage: 100 / 12 * N.

.col-1   โ†’  8.333โ€ฆ%
.col-2   โ†’ 16.666โ€ฆ%
.col-3   โ†’ 25%
.col-4   โ†’ 33.333โ€ฆ%
.col-6   โ†’ 50%
.col-8   โ†’ 66.666โ€ฆ%
.col-9   โ†’ 75%
.col-12  โ†’ 100%

Classes exist for every integer 1โ€“12.

Responsive columns โ€” .col-{bp}-N

Each column class has a breakpoint variant that applies at min-width. Breakpoints:

Name Min-width
sm 26.25rem (420px)
md 48rem (768px)
lg 64rem (1024px)
xl 85.375rem (1366px)
xxl 105rem (1680px)

The base .col-N (no breakpoint) applies at all widths. Layer responsive classes on top for wider viewports:

<!-- Full width on mobile, half at md, third at lg -->
<div class="col-12 col-md-6 col-lg-4">โ€ฆ</div>

Full responsive example โ€” the twelve columns are drawn behind it, so press the width buttons and watch each card land on twelve, six and four of them:

<div class="grid grid-gutter container">
  <div class="col-12 col-md-6 col-lg-4"><div class="bg-gray-200 p-16">Card A</div></div>
  <div class="col-12 col-md-6 col-lg-4"><div class="bg-gray-200 p-16">Card B</div></div>
  <div class="col-12 col-md-12 col-lg-4"><div class="bg-gray-200 p-16">Card C</div></div>
</div>

Offsets โ€” .col-offset-N

Pushes a column right by adding margin-left as a percentage of the parent. Range: 0โ€“11.

.col-offset-0   โ†’ margin-left: 0%
.col-offset-1   โ†’ margin-left: 8.333โ€ฆ%
.col-offset-6   โ†’ margin-left: 50%
.col-offset-11  โ†’ margin-left: 91.666โ€ฆ%

Responsive variants follow the same pattern: .col-offset-{bp}-N.

<div class="grid grid-gutter">
  <div class="col-6 col-offset-3"><div class="bg-gray-200 p-16">Centered 6-column block</div></div>
</div>

.grid-reverse

Add .grid-reverse to a .grid row to set flex-direction: row-reverse. When .grid-reverse is present, offset classes switch from margin-left to margin-right, so offsets keep working visually in the reversed direction.

Flex-only โ€” flex-direction does nothing on a .d-grid container. Native grid reverses with direction: rtl or explicit line placement.

<div class="grid grid-gutter grid-reverse">
  <div class="col-4 col-offset-2"><div class="bg-gray-200 p-16">Pushed from the right</div></div>
</div>

Max-width columns โ€” .col-N-max

.col-N-max caps an element's max-width to N columns' worth of the largest breakpoint (xxl, 1680px), accounting for container offsets and gutters. Range: 1โ€“11 (.col-12-max is not generated; use the container's full width instead).

The value is computed in px from the max breakpoint width minus container padding on both sides plus one gutter unit, scaled by the column fraction, then converted once at the end:

desktop: (1680 - 56ร—2 + 32) ร— (N/12)  โ†’  1600 ร— (N/12)
mobile:  (1680 - 16ร—2 + 16) ร— (N/12)  โ†’  1664 ร— (N/12)

Examples (desktop):

.col-6-max   โ†’ max-width: 50rem    (800px)
.col-4-max   โ†’ max-width: ~33.3rem (~533px)
.col-3-max   โ†’ max-width: 25rem    (400px)

Use .col-N-max when you want an element to grow freely on small screens but never exceed the proportional column width at full desktop scale.

<img class="col-6-max" src="photo.jpg" alt="">

Native CSS grid

Separate from the 12-column flex system above, these utilities drive a real display: grid container.

Class CSS
.d-grid display: grid
.d-inline-grid display: inline-grid

Every class in this section spells out the axis as column / row, never col โ€” matching .flex-column in Flexbox, and keeping the flex grid's .col-* namespace clear.

All of them generate responsive variants, with the breakpoint before the value: .grid-cols-md-3, .grid-column-span-lg-4, .grid-flow-md-column.

Track templates

Class CSS
.grid-cols-{n} grid-template-columns: repeat({n}, minmax(0, 1fr))
.grid-rows-{n} grid-template-rows: repeat({n}, minmax(0, 1fr))

Columns run 1โ€“12 ($columns), rows 1โ€“6 ($rows). Rows stop at 6 on purpose: grid-template-rows only does visible work on a container with a definite height, and templates that deep are rare. Raise $rows if you need more.

The minmax(0, 1fr) โ€” rather than plain 1fr โ€” is what stops a long word or a wide <pre> from blowing a track past its share.

Pair with the .gap-* utilities for gutters.

<div class="d-grid grid-cols-1 grid-cols-md-3 gap-16">
  <div class="bg-gray-200 p-16">Cell A</div>
  <div class="bg-gray-200 p-16">Cell B</div>
  <div class="bg-gray-200 p-16">Cell C</div>
</div>

Rows need a height to divide, so give the container one:

<div class="d-grid grid-rows-3 gap-8 h-100vh">
  <header>Fixed third</header>
  <main>Fixed third</main>
  <footer>Fixed third</footer>
</div>

Item spans

Class CSS
.grid-column-span-{n} grid-column: span {n} / span {n}
.grid-column-span-full grid-column: 1 / -1
.grid-row-span-{n} grid-row: span {n} / span {n}
.grid-row-span-full grid-row: 1 / -1

{n} matches the track ranges โ€” 1โ€“12 for columns, 1โ€“6 for rows. -full spans the first line to the last regardless of how many tracks the container has, which is the one that survives a change to .grid-cols-*.

<div class="d-grid grid-cols-3 gap-16">
  <div class="grid-column-span-full bg-gray-200 p-16">Full-width heading</div>
  <div class="grid-column-span-2 bg-gray-200 p-16">Two thirds</div>
  <div class="bg-gray-200 p-16">One third</div>
</div>

Auto-flow โ€” .grid-flow-*

Controls where items land when they have no explicit placement.

Class CSS
.grid-flow-row grid-auto-flow: row
.grid-flow-column grid-auto-flow: column
.grid-flow-dense grid-auto-flow: dense
.grid-flow-row-dense grid-auto-flow: row dense
.grid-flow-column-dense grid-auto-flow: column dense

row is the CSS default โ€” the class exists to undo a column set at a narrower breakpoint. dense backfills holes left by spanning items instead of leaving gaps, at the cost of items appearing out of source order (which is also what it does to keyboard and screen-reader order, so use it for galleries, not for content that has to be read in sequence).

.grid-flow-dense on its own is row dense. The two combined forms exist because grid-auto-flow is one property โ€” .grid-flow-column.grid-flow-dense cannot work, the second class just wins.

<!-- Masonry-ish gallery: no gaps, source order not guaranteed -->
<div class="d-grid grid-cols-4 gap-8 grid-flow-row-dense">
  <img class="grid-column-span-2" src="wide.jpg" alt="">
  <img src="a.jpg" alt="">
  <img src="b.jpg" alt="">
</div>

Alignment

place-items and place-content set both axes at once โ€” the row axis (align-*) and the column axis (justify-*) โ€” so .place-center is a one-class replacement for .align-center.justify-center.

Prefix: place Property: place-items

Class CSS
.place-normal place-items: normal
.place-center place-items: center
.place-start place-items: start
.place-end place-items: end
.place-stretch place-items: stretch

Prefix: place-content Property: place-content

Class CSS
.place-content-normal place-content: normal
.place-content-center place-content: center
.place-content-start place-content: start
.place-content-end place-content: end
.place-content-stretch place-content: stretch
.place-content-space-between place-content: space-between
.place-content-space-around place-content: space-around

place-items aligns each item inside its own track; place-content aligns the track grid as a whole inside the container. Both prefixes generate responsive variants (.place-md-center, .place-content-lg-start).

<div class="d-grid grid-cols-3 gap-16 place-center">
  <div class="bg-gray-200 p-16">Centered in its cell</div>
  <div class="bg-gray-200 p-16">Centered in its cell</div>
  <div class="bg-gray-200 p-16">Centered in its cell</div>
</div>