Skip to content

Layout Recipes

Layout recipes provide consistent patterns for organizing content. They replace verbose utility classes with semantic, readable class names.

Airframe favors layout recipes over atomic class soup:

<section class="af-stack af-gap-lg">
  <h1 class="af-text-h1">
    Readable layout
  </h1>
  <p class="af-text-muted">
    Clear structure, predictable classes.
  </p>
</section>

Vertical stacking layout for arranging items in a column.

<div class="af-stack">
  <div class="af-card">
    Item 1
  </div>
  <div class="af-card">
    Item 2
  </div>
  <div class="af-card">
    Item 3
  </div>
</div>
<div class="af-stack-sm">
  Small spacing
</div>
<div class="af-stack">
  Default spacing (md)
</div>
<div class="af-stack-md">
  Medium spacing
</div>
<div class="af-stack-lg">
  Large spacing
</div>

Horizontal layout with wrapping for arranging items in a row.

<div class="af-inline af-gap-sm">
  <button class="af-btn">
    Save
  </button>
  <button class="af-btn af-is-secondary">
    Cancel
  </button>
</div>
  • af-cluster - Default semantic cluster (items centered, wrapping)
  • af-spread - Items spread with space-between
  • af-center - Items centered
<!-- Cluster (default) -->
<div class="af-cluster">
  <button class="af-btn">
    Action 1
  </button>
  <button class="af-btn">
    Action 2
  </button>
</div>
<!-- Spread -->
<div class="af-spread">
  <span>
    Left content
  </span>
  <button class="af-btn">
    Right action
  </button>
</div>
<!-- Center -->
<div class="af-center">
  <button class="af-btn">
    Centered button
  </button>
</div>

CSS Grid-based layout system for responsive columns.

<!-- Auto-adjusts to number of children -->
<div class="af-grid">
  <div>
    Item 1
  </div>
  <div>
    Item 2
  </div>
  <div>
    Item 3
  </div>
</div>
<!-- Explicit columns -->
<div class="af-grid-2">
  <div>
    Item 1
  </div>
  <div>
    Item 2
  </div>
</div>
<!-- 1 column on mobile, 2 on tablet, 3 on desktop -->
<div class="af-grid-1 af-grid-2@md af-grid-3@lg">
  <div>
    Item 1
  </div>
  <div>
    Item 2
  </div>
  <div>
    Item 3
  </div>
</div>

For asymmetric layouts:

<div class="af-grid">
  <div class="af-col-span-8@lg">
    Main content
  </div>
  <div class="af-col-span-4@lg">
    Sidebar
  </div>
</div>

Centered container with max-width:

<div class="af-container">
  <div class="af-stack">
    <h1>
      Page Title
    </h1>
    <p>
      Content goes here
    </p>
  </div>
</div>

Use one class per element: af-container-xl, not af-container af-container-xl.

  • af-container-xs - 25rem
  • af-container-sm - 40rem
  • af-container - Default (90em)
  • af-container-md - 48rem
  • af-container-lg - 64rem
  • af-container-xl - 80rem
  • af-container-2xl - 96rem
<div class="af-card">
  <div class="af-card__header">
    <h3 class="af-card__title">
      Title
    </h3>
  </div>
  <div class="af-card__body">
    <p>
      Content
    </p>
  </div>
  <div class="af-card__footer">
    <button class="af-btn">
      Action
    </button>
  </div>
</div>
<form class="af-form">
  <div class="af-stack af-gap-md">
    <div class="af-field">
      <label class="af-field__label" for="email">
        Email
      </label>
      <input type="email" id="email" class="af-input" />
    </div>
    <button type="submit" class="af-btn">
      Submit
    </button>
  </div>
</form>
<div class="af-container">
  <header class="af-stack af-gap-sm">
    <h1>
      Page Title
    </h1>
    <p class="af-text-muted">
      Subtitle
    </p>
  </header>
  <main class="af-stack af-gap-lg">
    <section class="af-card">
      <div class="af-card__body">
        Content
      </div>
    </section>
  </main>
</div>

Layout recipes work together:

<div class="af-container">
  <div class="af-stack af-gap-lg">
    <header class="af-spread">
      <h1>
        Dashboard
      </h1>
      <button class="af-btn">
        New Item
      </button>
    </header>
    <div class="af-grid-1 af-grid-2@md af-grid-3@lg af-gap-md">
      <div class="af-card">
        Card 1
      </div>
      <div class="af-card">
        Card 2
      </div>
      <div class="af-card">
        Card 3
      </div>
    </div>
  </div>
</div>