Actual CSS

Grid

Choose what determines the column count:

  • The item width is what matters — use .grid and tune --grid-min.
  • The column density is what matters — use .grid-2, .grid-3, .grid-4, or .grid-6.

Space-driven collection

.grid fits as many columns as the available inline space permits. Incomplete final rows are part of the contract.

Starter

For small projects.

Team

For shared products.

Scale

For larger systems.

<section class="grid">
  <article class="card"><h3>Starter</h3><p>For small projects.</p></article>
  <article class="card"><h3>Team</h3><p>For shared products.</p></article>
  <article class="card"><h3>Scale</h3><p>For larger systems.</p></article>
</section>

Tune the item minimum with --grid-min.

.pricing-grid {
  --grid-min: 20rem;
}

Count-driven density

.grid-N fits up to N equal-width columns and reduces the count as space narrows. It is responsive without a container wrapper.

Exercitation
Amet mollit
Aute cillum
Duis non
<div class="grid-4">
  <div class="card">Exercitation</div>
  <div class="card">Amet mollit</div>
  <div class="card">Aute cillum</div>
  <div class="card">Duis non </div>
</div>

--grid-min applies only to .grid. Choose a preset that suits your item size:

ItemPreset
large card.grid-2
card with a heading and a summary.grid-3, .grid-4
compact tile, stat, avatar.grid-6

Balanced subdivision

Left alone, a preset collapses one column at a time, so a six-item .grid-6 can pass through five columns — five items and a lone sixth. The example above is that bare version. Placed inside a container named actual-container — the .container-query helper, or a region of your own that declares container: actual-container / inline-size — it only ever enters a divisor of N:

.grid-2   2 → 1
.grid-3   3 → 1
.grid-4   4 → 2 → 1
.grid-6   6 → 3 → 2 → 1

Every state splits the collection evenly, and all items keep the same width.

1
2
3
4
5
6
<div class="container-query">
  <div class="grid-6">
    <div class="card">1</div>
    <div class="card">2</div>
    <div class="card">3</div>
    <div class="card">4</div>
    <div class="card">5</div>
    <div class="card">6</div>
  </div>
</div>

Container sizes

The steps are read from the container's content box — not the viewport, and not the grid's own width. Padding and borders on the container come off before the query resolves.

Container content box.grid-2.grid-3.grid-4.grid-6
under 28rem1111
28rem to 48rem2122
48rem to 64rem2323
64rem and up2346

Size a region that hosts a .grid-N so it lands on the step you want, with room to spare. The step is a cliff, not a ramp: a container at 47rem gives .grid-3 a single column, the same as one at 20rem. .grid-3 has no intermediate state by design — it never shows 2 + 1.

Budget backwards from the content box. A region that must reach a step needs that width plus its own padding and borders:

3 columns   48rem + 2 x 1rem padding  ~= 50rem outer
4 or 6      64rem + 2 x 1rem padding  ~= 66rem outer

Round up past the figure rather than matching it exactly, so a later padding change cannot drop the region a state.

Use a normal block-level ancestor as the named container, keeping it separate from the grid. Only the name actual-container enables balanced subdivision; an unnamed query container leaves the baseline behavior unchanged. The same named container can serve both a grid and a step flow.

The chain balances the declared density, not your actual item count. Eight items in .grid-6 still give 6 + 2. For a paginated collection, choose a page size that suits the density — 12, 20, and 24 divide well. A partial final page is normal.

Exact templates

--grid-columns replaces .grid's intrinsic recipe. Use it for exact track templates that do not match a built-in layout contract: arbitrary structural counts such as seven calendar days, asymmetric fractional tracks, or mixed intrinsic/flexible tracks. Once set, the application owns narrow-container behavior.

/* Semantic count not represented by .grid-N */
--grid-columns: repeat(7, minmax(0, 1fr));

/* Meaningful asymmetric ratio */
--grid-columns: 2fr 1fr 1fr 1fr;

/* Intrinsic trailing control */
--grid-columns: repeat(4, minmax(0, 1fr)) auto;
<div class="container-query">
  <div class="editorial-grid grid">...</div>
</div>
.editorial-grid {
  --grid-columns: minmax(0, 2fr) minmax(0, 1fr);
}

@container (width < 40rem) {
  .editorial-grid {
    --grid-columns: 1fr;
  }
}

For an ordinary main region plus an aside, prefer .sidebar-layout. When a small group of peer regions must be either entirely horizontal or entirely stacked, prefer .switcher.

Hooks

  • --grid-min tunes the minimum item width of the intrinsic .grid recipe. It does not apply to .grid-N.
  • --grid-columns replaces that recipe with an author-owned template.

Both stop at a nested .grid: set them on the grid itself.

Actual CSS

Search documentation