Core layout utilities: flex, grid and spacing

Build page structure with display, flex and grid utilities, prefer gap over margin tricks, and place things with positioning and insets.

Flexbox

<div class="flex items-center justify-between gap-4 p-4">
  <div class="flex min-w-0 items-center gap-3">
    <img class="size-10 shrink-0 rounded-full object-cover" src="avatar.jpg" alt="">
    <div class="min-w-0">
      <p class="truncate font-medium">Ada Lovelace</p>
      <p class="truncate text-sm text-slate-500">ada@example.com</p>
    </div>
  </div>
  <button class="shrink-0 rounded-md bg-slate-900 px-3 py-1.5 text-white">Edit</button>
</div>
UtilityCSSNote
flexdisplay: flexThe container
flex-1flex: 1 1 0%Grow evenly, ignore content size
growflex-grow: 1Grow, but keep the base size
shrink-0flex-shrink: 0Refuse to be squeezed
items-centeralign-items: centerCross-axis alignment
justify-betweenjustify-content: space-betweenMain-axis distribution
basis-1/3flex-basis: 33.33%Starting size before growth
💡
Text inside a flex child will not shrink below its longest word unless the child has min-w-0. That single missing class is why a long email address pushes a layout sideways instead of being truncated - the flex item's minimum size defaults to its content.

Grid

<div class="grid grid-cols-1 gap-6 sm:grid-cols-2 lg:grid-cols-3">
  <article class="rounded-lg border p-4">...</article>
  <article class="rounded-lg border p-4">...</article>
  <article class="rounded-lg border p-4">...</article>
</div>

<!-- spans and named placement -->
<div class="grid grid-cols-6 gap-4">
  <div class="col-span-6 lg:col-span-4">main</div>
  <aside class="col-span-6 lg:col-span-2">sidebar</aside>
</div>

<!-- an auto-fitting gallery, with no breakpoints at all -->
<div class="grid grid-cols-[repeat(auto-fill,minmax(12rem,1fr))] gap-4">
  <img class="aspect-square w-full rounded object-cover" src="one.jpg" alt="">
</div>
<!-- named grid areas, expressed as an arbitrary property -->
<div class="grid grid-cols-3 grid-rows-[auto_1fr_auto]">
  <header class="col-span-3">Header</header>
  <main>Content</main>
  <aside>Sidebar</aside>
  <footer class="col-span-3">Footer</footer>
</div>
  • gap-* replaces the margin-on-children pattern and does not add space around the outside of the grid.
  • grid-cols-[repeat(auto-fill,minmax(...))] gives responsive behaviour without a single breakpoint prefix.
  • Put a fixed grid-rows on a layout shell when you want the content row to take the remaining height.
  • Reach for grid when you are placing things in two dimensions, and flex when you are distributing a row or a column of items.

Spacing, sizing and positioning

<!-- space between siblings: gap, never space-x -->
<div class="flex gap-3">...</div>
<div class="grid gap-3">...</div>

<!-- a centred, bounded page column -->
<div class="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8">...</div>

<!-- aspect ratio, object fit and full-size media -->
<div class="aspect-video overflow-hidden rounded-lg">
  <img class="size-full object-cover" src="hero.jpg" alt="">
</div>

<!-- sticky header over a scroll container -->
<header class="sticky top-0 z-40 border-b bg-white/80 backdrop-blur">...</header>

<!-- an overlay pinned to its nearest positioned ancestor -->
<div class="relative">
  <span class="absolute inset-0 rounded ring-2 ring-sky-500"></span>
  <span class="absolute -top-1 -right-1 size-3 rounded-full bg-red-500"></span>
</div>
ClassProduces
gap-4gap: calc(var(--spacing) * 4)
p-4 / px-4 / pt-4Padding, all or one side
size-10Width and height in one utility
mx-autoCentres a block with a max width
inset-0Pins all four edges, for full-bleed overlays
-mt-2Negative margin, for optical alignment
z-40Stacking order on a positioned element
aspect-videoaspect-ratio: 16 / 9
/* the spacing scale is one variable, so changing it rescales everything */
@theme {
  --spacing: 0.25rem;      /* gap-4 is 1rem; set a different base and the whole UI follows */
}

Prefer gap to space-x-*. Gap applies between items without touching the outside edges, it composes with wrapping, and it needs no selector trickery that can surprise a flex child.

FAQ

When should I use grid instead of flex?
Flex for one dimension: a toolbar, a list of badges, a card's internal rows. Grid for two dimensions, for equal columns that must line up across rows, or for anything that needs a span. If you find yourself adding a fixed basis and a wrapping class to a flex row to fake a grid, it is a grid.
Why is my long text overflowing its container?
A flex or grid child defaults to a minimum size of its content, so it refuses to shrink. Add min-w-0 to the child, then truncate or break-words to the text. This is the most common layout bug in utility-first CSS.

Utility-first basics Component patterns without a component library

Last refreshed 2026-09-18.