Command Palette

Search for a command to run...

Hectal
PHASE 7Intermediate ~29 min· topic 5 of 5

Topic 7.5

Flexbox Patterns

In one line

Five layouts cover most of what Flexbox is used for: a navbar (auto margin), a media object (fixed image plus flex: 1; min-width: 0 text), a row of equal-height cards with buttons pinned to the bottom, a sticky footer (column + flex: 1 main) and the holy grail page layout.

Think of it like this

Recipes in a cookbook. Once you know how to boil, fry and bake, you don't invent dinner from scratch each night: you follow a handful of tried recipes and adjust them. Layout works the same way. With the tools from Topics 7.1–7.4 you can cook five patterns that appear on almost every website, and each one is only a few lines of CSS.

Words you'll meet

New words in this topic, in plain English. Come back here whenever one feels fuzzy.

Pattern
A well-known solution to a layout problem that comes up again and again.
Navbar
The bar of site links, usually at the top of a page, with a logo and maybe a button.
Media object
An image beside a block of text, like a comment with an avatar.
Equal-height cards
Cards in a row that all match the tallest one, so their edges line up.
Sticky footer
A footer that stays at the bottom of the window when the page is short, and after the content when it's long.
`100dvh`
100% of the dynamic viewport height: the visible window height, updated as mobile browser bars appear and disappear.
Holy grail layout
A page with a header, a footer and three columns between them: nav, main and sidebar.
Nesting
Putting a flex container inside a flex item, so the item lays out its own children with Flexbox too.

Step by step

01Navbar: centre and split

The nav is a row, centred on the cross axis. The links list is pushed right by its auto margin. The list is a flex row too.

style.csswhole filecss
nav {
  display: flex;
  align-items: center;
  gap: 16px;
}
nav ul {
  display: flex;
  gap: 12px;
  margin: 0 0 0 auto; /* push the links to the right */
  padding: 0;
  list-style: none;
}

02Media object: protect the image, free the text

The image never shrinks; the text takes the rest and can shrink below its content width.

style.csswhole filecss
.media { display: flex; align-items: flex-start; gap: 12px; }
.media img { flex: none; width: 48px; height: 48px; }
.media .body { flex: 1; min-width: 0; }

03Card row: equal heights, aligned buttons

The outer row stretches every card to the same height. Each card is a column, and margin-top: auto on the button pushes it to the bottom.

style.csswhole filecss
.cards { display: flex; gap: 12px; }
.card { flex: 1; display: flex; flex-direction: column; }
.card button { margin-top: auto; }

04Sticky footer: let main take the spare height

The body is a column at least one screen tall; main grows into the spare height.

style.csswhole filecss
body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh; /* newer browsers use this line */
  display: flex;
  flex-direction: column;
}
main { flex: 1; }
Sticky footer: let main take the spare heightdiagram
Rendering diagram…

05Holy grail: a column with a row inside

Combine the sticky footer with a three-column row in the middle, and stack the row on narrow screens.

style.csswhole filecss
.middle { flex: 1; display: flex; }
.middle nav, .middle aside { flex: 0 0 180px; }
.middle main { flex: 1; min-width: 0; }
@media (max-width: 600px) {
  .middle { flex-direction: column; }
  .middle nav, .middle aside { flex-basis: auto; }
}

Try it yourself

  1. 1

    Move the split

    In the navbar, move margin-left: auto from the ul to the button. Predict the layout: the logo and links stay together on the left and only the button goes right. Check that the first console line is still true.

  2. 2

    Truncate the media text

    In the media object, add white-space: nowrap; overflow: hidden; text-overflow: ellipsis; to .media p. Predict the text column's width. (Still 200, because min-width: 0 lets it ignore the long line.) Then remove min-width: 0 and predict again.

  3. 3

    Let the cards wrap

    In the card row, add flex-wrap: wrap to .cards and change the cards to flex: 1 1 120px. Predict how many cards fit per line in a 270px row, and whether the heights stay equal. (Two fit; heights are equal only within each line.)

Code & diagrams

Navbar with a split New tab

Make the preview wider: the logo stays left, the links and button stay right, and the gap between the two groups grows. All three groups are centred on the same horizontal line, even though the logo's font is bigger.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

button at the right edge: true
logo at the left edge: true
logo and button share a middle: true
Media object New tab

The image keeps 48 x 48 even though the text is long; the text column gets 260 - 48 - 12 = 200px. Change `align-items` to the default `stretch`: an `<img>` stretched down would distort, which is why the pattern pins it to the top.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

image: 48 x 48
text column: 200
image is taller than the text: false
Equal-height cards with buttons at the bottom New tab

The middle card has much more text, yet all three cards are the same height (the row's `align-items: stretch`) and the buttons line up (`margin-top: auto` inside each column). Delete `margin-top: auto` and run again: the buttons follow their text.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

equal heights: true
buttons line up: true
equal widths: true
Sticky footer New tab

The page content is short, but `main` grows to fill the spare height, so the footer sits at the bottom of the window. Add many paragraphs to `main`: the page becomes taller than the window and the footer follows the content.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Expected console output

footer touches the bottom of the window: true
main grew taller than its text: true
Holy grail layout New tab

In a narrow preview the three middle parts stack; widen it past 400px and they become three columns. Grid with named areas (Topic 8.4) describes the same page in fewer lines.

Preview

Press Run to see the page.

Console

Nothing logged yet.

Break it on purpose

Errors are the best teachers. Make each change, read the error, guess what went wrong, then reveal the answer.

Break #1

Use height instead of min-height

In the sticky footer example, change min-height: 100vh to height: 100vh and add twenty paragraphs to main.

terminal
$ Preview
── what you'll see ──
The footer stays at the bottom of the first screen and the extra text runs over and behind it as you scroll.

Break #2

Card buttons don't line up

In the card row, remove display: flex; flex-direction: column; from .card but keep margin-top: auto on the button.

terminal
$ Console
── what you'll see ──
equal heights: true
buttons line up: false
equal widths: true

Myth vs fact

Myth

Equal-height columns need JavaScript or table layout.

Fact

Flex items in a row stretch to the tallest item by default (align-items: stretch).

Myth

A sticky footer needs position: fixed.

Fact

A fixed footer covers content and stays on screen. A sticky-footer layout only uses spare height: a column with flex: 1 on main.

Myth

Flexbox can't do page layouts; you need Grid.

Fact

Flexbox can build the holy grail. Grid is usually clearer for two-dimensional page layouts, and Flexbox is usually better inside components.

Pro corner

Extra depth for experienced readers. New to this? Skip it for now and come back later.

  • ▸

    100vh on mobile is the large viewport height (toolbars hidden), so content sized with it can sit under the browser's bottom bar. svh (small), lvh (large) and dvh (dynamic) units fix that; write min-height: 100vh first and min-height: 100dvh second so older browsers keep the first value.

  • ▸

    For a media object holding an <img>, set width and height attributes on the image too: the browser reserves the space before the image loads, avoiding layout shift (CLS, a Core Web Vital).

  • ▸

    Nested flex containers multiply layout passes: a stretched item with flex-basis: auto may be laid out twice (once to measure, once to stretch). In long feeds, keep nesting shallow and prefer definite sizes for repeated items.

  • ▸

    Use logical properties in patterns that ship to many languages: margin-inline-start: auto instead of margin-left: auto, so a right-to-left navbar splits the right way without extra CSS.

Remember this

  1. 1

    Navbar. A <nav> is a flex row with align-items: center so the logo, links and button line up through their middles, and gap spaces them. To split the bar into a left group and a right group, give the first item of the right group margin-left: auto (or margin-inline-start: auto, which also works right to left). The auto margin eats all the free space (Topic 7.2). The link list itself is a <ul> that is also a flex row: Flexbox containers nest freely.

  2. 2

    Media object. A picture (an avatar, a thumbnail, an icon) beside a block of text: comments, chat messages, notifications. The image gets flex: none (or flex-shrink: 0) so it never gets squeezed, and the text gets flex: 1; min-width: 0 so it takes the rest and wraps or truncates instead of pushing the row wider. align-items: flex-start keeps the image at the top when the text is tall; the default stretch would stretch a non-image element down the whole height.

  3. 3

    Card row. Cards sit side by side with display: flex and gap, and the default align-items: stretch makes them equal height for free, whatever their text. Inside, each card is a column flex container, and the button at the bottom gets margin-top: auto, so every button is pushed to the bottom edge and the buttons line up across cards. Add flex-wrap: wrap and a basis to let the cards wrap on small screens.

  4. 4

    Sticky footer. On a short page the footer should sit at the bottom of the window, not halfway up. Make <body> a column flex container at least as tall as the viewport, min-height: 100vh (or 100dvh, the dynamic viewport height, which follows mobile browser toolbars as they show and hide), and give <main> flex: 1. Main takes all the spare height, pushing the footer down. On a long page there's no spare height and the footer follows the content normally. Use min-height, not height, or long pages get cut off.

  5. 5

    Holy grail. The classic page: a header, a footer, and between them three columns, navigation on the left, main content in the middle and a sidebar on the right. With Flexbox: body is a column (as in the sticky footer), the middle section is a row, the side columns have fixed bases (flex: 0 0 200px) and main has flex: 1; min-width: 0. On narrow screens a media query switches the middle row to flex-direction: column. This works well, but whole-page layouts that need rows and columns to line up are exactly what Grid with grid-template-areas (Topic 8.4) does more clearly.

  6. 6

    When to choose Flexbox for a pattern: when the layout is one direction (a row or a column), the number or size of items comes from the content, and you want items to share space. Choose Grid (Phase 8) when you design the rows and columns first and drop content into them. Many real layouts use both: Grid for the page, Flexbox inside each component.

Explain it without notes

01

How do you build a navbar with a logo on the left and links on the right using Flexbox?

02

What makes a media object robust when the text is very long?

03

How do you make cards in a row equal height with their buttons aligned at the bottom?

04

Explain how a Flexbox sticky footer works, and why min-height matters.

Practice

01

Build a notification row: a 32px icon, a message that takes the remaining space, and a "Dismiss" button at the far right, all centred vertically.

02

Make a page whose footer sits at the bottom of the window when the content is short.

03

Make three pricing cards equal height with their "Buy" buttons lined up at the bottom.

Trade-offs

  • ↔

    Flexbox patterns adapt to content with very little CSS, but rows that wrap can't keep columns aligned; switch to Grid when alignment across rows matters (a pricing table with matching feature rows, a photo grid).

  • ↔

    A holy grail in Flexbox needs nested containers and a media query; in Grid it's one container with named areas. Flexbox is still fine when the structure is simple and you already have the column wrapper.

Done when you can

  • I can build a navbar with a left and a right group.

  • I can build a media object that survives long text.

  • I can make equal-height cards with aligned buttons.

  • I can build a sticky footer and explain why it uses min-height.

  • I can build a holy grail layout that stacks on narrow screens.

  • I can say when a pattern is better done with Grid.