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>| Utility | CSS | Note |
|---|---|---|
flex | display: flex | The container |
flex-1 | flex: 1 1 0% | Grow evenly, ignore content size |
grow | flex-grow: 1 | Grow, but keep the base size |
shrink-0 | flex-shrink: 0 | Refuse to be squeezed |
items-center | align-items: center | Cross-axis alignment |
justify-between | justify-content: space-between | Main-axis distribution |
basis-1/3 | flex-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-rowson 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>| Class | Produces |
|---|---|
gap-4 | gap: calc(var(--spacing) * 4) |
p-4 / px-4 / pt-4 | Padding, all or one side |
size-10 | Width and height in one utility |
mx-auto | Centres a block with a max width |
inset-0 | Pins all four edges, for full-bleed overlays |
-mt-2 | Negative margin, for optical alignment |
z-40 | Stacking order on a positioned element |
aspect-video | aspect-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.Related
Utility-first basics Component patterns without a component library
Last refreshed 2026-09-18.