Flexbox lays items out in one direction, a row or a column, and is best for toolbars, nav bars and centring. Grid places items in rows and columns at once and suits page layouts and card galleries. Set display: flex or display: grid on the parent, then use the properties below; every one updates a live container here.
| Layout | Pick |
|---|---|
| Centre one thing in a box | Either: grid with place-items: center is shortest |
| A row of buttons or nav links | Flexbox |
| Items of unknown width that should wrap | Flexbox with flex-wrap |
| Cards in equal columns | Grid with repeat(auto-fill, minmax()) |
| Header, sidebar, main, footer | Grid with grid-template-areas |
| Line up items across rows and columns | Grid |
Updated
Two live containers, one flex and one grid, with a control for every container property and for one chosen item. Each change shows the CSS and the Tailwind class. Below them, paint a page layout into the grid-template-areas builder and copy the result. The reference tables print cleanly.
| Property | Values | Default | What it does | Tailwind |
|---|---|---|---|---|
| flex-direction | row | row-reverse | column | column-reverse | row | Main axis direction | flex-row, flex-row-reverse, flex-col, flex-col-reverse |
| flex-wrap | nowrap | wrap | wrap-reverse | nowrap | Whether items wrap onto new lines | flex-nowrap, flex-wrap, flex-wrap-reverse |
| justify-content | flex-start | center | flex-end | space-between | space-around | space-evenly | flex-start | Spread items along the main axis | justify-start, justify-center, justify-end, justify-between, justify-around, justify-evenly |
| align-items | stretch | flex-start | center | flex-end | baseline | stretch | Line items up on the cross axis | items-stretch, items-start, items-center, items-end, items-baseline |
| align-content | normal | flex-start | center | flex-end | space-between | space-around | stretch | normal | Spread wrapped lines on the cross axis | content-normal, content-start, content-center, content-end, content-between, content-around, content-stretch |
| gap | 0 | 8px | 16px | 32px | 0 | Space between items | gap-0, gap-2, gap-4, gap-8 |
| Property | Values | Default | What it does | Tailwind |
|---|---|---|---|---|
| flex-grow | 0 | 1 | 2 | 0 | Share of spare space the item takes | grow-0, grow, grow-[2] |
| flex-shrink | 1 | 0 | 1 | Whether the item may shrink below its basis | shrink, shrink-0 |
| flex-basis | auto | 0 | 120px | 50% | auto | Starting size before growing or shrinking | basis-auto, basis-0, basis-[120px], basis-1/2 |
| order | 0 | -1 | 1 | 5 | 0 | Visual order (not reading order) | order-none, -order-1, order-1, order-5 |
| align-self | auto | flex-start | center | flex-end | stretch | auto | Override align-items for one item | self-auto, self-start, self-center, self-end, self-stretch |
| Property | Values | Default | What it does | Tailwind |
|---|---|---|---|---|
| grid-template-columns | 1fr 1fr 1fr | 200px 1fr | repeat(auto-fill, minmax(120px, 1fr)) | 1fr 2fr 1fr | 1fr 1fr 1fr | Column sizes | grid-cols-3, grid-cols-[200px_1fr], grid-cols-[repeat(auto-fill,minmax(120px,1fr))], grid-cols-[1fr_2fr_1fr] |
| grid-auto-rows | auto | 80px | minmax(60px, auto) | auto | Height of rows created automatically | auto-rows-auto, auto-rows-[80px], auto-rows-[minmax(60px,auto)] |
| grid-auto-flow | row | column | row dense | row | How items fill the grid | grid-flow-row, grid-flow-col, grid-flow-row-dense |
| justify-items | stretch | start | center | end | stretch | Align each item inside its cell horizontally | justify-items-stretch, justify-items-start, justify-items-center, justify-items-end |
| align-items | stretch | start | center | end | stretch | Align each item inside its cell vertically | items-stretch, items-start, items-center, items-end |
| gap | 0 | 8px | 16px | 32px | 8px | Space between rows and columns | gap-0, gap-2, gap-4, gap-8 |
| Property | Values | Default | What it does | Tailwind |
|---|---|---|---|---|
| grid-column | auto | span 2 | 1 / -1 | 2 / 4 | auto | Which columns the item covers | col-auto, col-span-2, col-span-full, col-start-2 col-end-4 |
| grid-row | auto | span 2 | 1 / 3 | auto | Which rows the item covers | row-auto, row-span-2, row-start-1 row-end-3 |
| justify-self | auto | start | center | end | stretch | auto | Horizontal alignment of one item | justify-self-auto, justify-self-start, justify-self-center, justify-self-end, justify-self-stretch |
| align-self | auto | start | center | end | stretch | auto | Vertical alignment of one item | self-auto, self-start, self-center, self-end, self-stretch |
Three named rows on wide screens. Change the areas in one place to rearrange the page.
<style>
.page { display: grid; gap: 8px; min-height: 200px;
grid-template-columns: 160px 1fr;
grid-template-rows: auto 1fr auto;
grid-template-areas: "head head" "side main" "foot foot" }
.page > * { background: #e0e7ff; padding: 8px; border-radius: 6px }
header { grid-area: head } aside { grid-area: side } main { grid-area: main } footer { grid-area: foot }
</style>
<div class="page"><header>Header</header><aside>Sidebar</aside><main>Main content</main><footer>Footer</footer></div>margin-left: auto on the last group pushes it to the far end, a common flexbox trick.
<nav style="display: flex; align-items: center; gap: 16px; padding: 10px; background: #0f172a; color: #fff; border-radius: 8px">
<strong>Harbour</strong>
<a href="#" style="color: #cbd5e1">Menu</a>
<a href="#" style="color: #cbd5e1">Hours</a>
<a href="#" style="margin-left: auto; color: #fff">Book a table</a>
</nav>Resize the window: the number of columns changes on its own.
<div style="display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 10px">
<div style="background: #fef3c7; padding: 20px; border-radius: 8px">Sourdough</div>
<div style="background: #fef3c7; padding: 20px; border-radius: 8px">Rye</div>
<div style="background: #fef3c7; padding: 20px; border-radius: 8px">Focaccia</div>
<div style="background: #fef3c7; padding: 20px; border-radius: 8px">Brioche</div>
<div style="background: #fef3c7; padding: 20px; border-radius: 8px">Bagels</div>
</div>| Row | Areas |
|---|---|
| 1 | header header header |
| 2 | sidebar main main |
| 3 | footer footer footer |
Every flex container has a main axis set by flex-direction and a cross axis at right angles to it. Properties starting with justify act on the main axis and properties starting with align act on the cross axis. Once that clicks, most flexbox puzzles become a question of which axis you mean.
Grid has a fixed pair of axes instead: inline (usually horizontal) and block (usually vertical). justify-* aligns along the inline axis and align-* along the block axis, for both the whole grid and items inside their cells.
Each item starts at its flex-basis, or its content size when basis is auto. If the line has room left, the spare space is shared in proportion to flex-grow. If the line is too full, items shrink in proportion to flex-shrink multiplied by their basis.
The shorthand flex: 1 means grow 1, shrink 1, basis 0%, so every item ends up the same width whatever its content. flex: auto keeps the content size as the starting point, so longer labels get wider boxes.
grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)) fits as many columns of at least 220 pixels as the container allows and stretches them to fill the row. Cards reflow from one column on a phone to four or five on a wide screen with no breakpoints.
auto-fit behaves the same until there are fewer items than columns: auto-fill keeps the empty columns, while auto-fit collapses them so the existing items stretch across the row.
justify-content works along the main axis, which in a flex row runs left to right. align-items works across it, top to bottom in a row. Switch flex-direction to column and the two swap physical directions, which is why centring sometimes seems to use the wrong property.
It only has an effect when there is spare space on the main axis. If an item has flex-grow: 1 or the items fill the row, nothing is left to distribute. In grid, justify-content moves the whole set of tracks, while justify-items aligns items inside their own cells.
You draw the layout as strings, one per row, with a name for each cell, such as "header header" "side main". Each child then claims a name with grid-area: header. Areas must form rectangles, and a dot marks an empty cell.
Yes, and it is common. Grid places the big regions or cards, and flexbox arranges the content inside each one, such as an icon next to a label or a footer pinned to the bottom of a card.
Yes. All current major browsers support gap in flex containers as well as grid, so the old trick of negative margins on the container is no longer needed.
Related: CSS grid generator, CSS layout generator, CSS text styling playground, PX to REM converter, Screen resolution checker.
Start for free or see all free tools. We.Inc is free to start, with no card needed. AI building is on paid plans from $20 a month.
We.Inc is an AI-powered website builder you can resell under your own brand. Launch a branded client dashboard, bill on Stripe Connect, and deliver AI-generated websites in minutes. White-label plans start at $99 a month for 25 client sites, with a 7-day free trial and no per-site fees.