Usage

The grid, the bleed and the setup, in HTML and CSS.

Basic layout

og-grid centres the columns, caps them at the max width and pads the sides. Its children span the whole content area until you place them.

html
<div class="og-grid">
  <aside class="sidebar">…</aside>
  <main class="content">…</main>
</div>
.sidebar
.content

The rest is your CSS. Any grid property works on the children:

css
.sidebar {
  grid-column: span 3;
}

.content {
  grid-column: span 9;
}

Placing items

Lines are numbered like in any grid. The lines also have names: content-start and content-end around the columns, col-start N and col-end N around column N.

css
.single {
  grid-column: col-start 5 / col-end 5;
}

.range {
  grid-column: col-start 2 / col-end 4;
}

.from {
  grid-column: col-start 7 / span 6;
}

.cover {
  grid-column: content;
  grid-row: 3;
}
.single
.range
.from
.cover

Responsive

There are no breakpoints of its own: a media query moves things like on any grid.

css
.card {
  grid-column: span 12;
}

@media (min-width: 48rem) {
  .card {
    grid-column: span 6;
  }
}

@media (min-width: 64rem) {
  .card {
    grid-column: span 4;
  }
}

Nesting

grid-template-columns: subgrid reuses the parent's columns instead of making new ones, so nested items stay aligned to the page. The gutter comes with them.

css
.articles {
  grid-column: span 8;
  display: grid;
  grid-template-columns: subgrid;
}

.articles > article {
  grid-column: span 4;
}
article
article
aside

Aligned rows

grid-template-rows: subgrid does the same for rows: sibling cards share them, so titles, text and footers line up even when the text is longer in one of them.

css
.card {
  grid-column: span 4;
  grid-row: span 3;
  display: grid;
  grid-template-rows: subgrid;
}
title
short text
footer
title
a longer text that wraps on more than one line and pushes the footer down
footer
title
short text
footer

Full bleed

og-full runs an item to the edges of the screen. og-start-full and og-end-full bleed one side only, and og-pl-bleed, og-pr-bleed and og-px-bleed bring the content back on the columns.

html
<div class="og-grid">
  <img class="og-full" />
  <nav class="og-start-full og-pl-bleed menu">…</nav>
</div>

Where the item ends is still your CSS: set only the side that doesn't bleed, so the class keeps the other. The classes have no breakpoints, but the distance to the edge is --og-bleed, so a media query bleeds only where you want it to:

css
.menu {
  grid-column-end: col-end 3;
}

@media (min-width: 64rem) {
  .cover {
    margin-inline: calc(var(--og-bleed) * -1);
  }
}

Without columns

og-container gives you the width and padding of the grid, without columns.

html
<header class="og-container">…</header>

Setup

Everything is a custom property. I set them once on :root, after the import:

css
@import "outgrid";

:root {
  --og-columns: 12;
  --og-max-width: 90rem;
  --og-padding: 1rem;
  --og-gutter-x: 2rem;
  --og-gutter-y: 2rem;
}

Every class has zero specificity, so any rule of yours wins over the defaults and a single grid can change without touching the properties:

css
.compact {
  row-gap: 0;
}

Reference

class
og-gridthe grid: centred, capped at the max width, padded on both sides
og-containerthe width and padding of the grid, without columns
og-fulledge to edge of the screen
og-contentthe whole content area; cancels any bleed
og-start-fullbleeds off the left edge
og-end-fullbleeds off the right edge
og-pl-bleed / pr / pxpadding as wide as the bleed, to bring content back on the columns
token
--og-columnsnumber of columns; 12 by default
--og-max-widththe widest the content area gets, padding excluded
--og-paddingside padding of the grid
--og-gutter-xspace between columns
--og-gutter-yspace between rows
--og-bleeddistance from the content area to the edge of the screen; computed, read it, don't set it