0 / 91
Week 2 · Day 12 of 91

Flexbox, Grid, and responsive layout

HTML, CSS, Git, and the First Website

Objective

Build layouts that adapt rather than relying on fixed coordinates.

HTML is the mechanical structure, CSS is the physical layout and finish, and Git is the revision history for every design change.

  • one-dimensional flex layout
  • two-dimensional grid
  • media queries and fluid sizing

Why this matters

Your page currently works at whatever width your laptop happens to be. Today you make it work at any width — a 375px phone and a wide desktop — using layout that adapts instead of layout that is pinned to coordinates.

This is not decoration. More than half of real web traffic is phones, and a page that needs sideways scrolling to read is a broken page. By the end you will have one stylesheet that produces a single column when space is tight and multiple columns when it is not.

Normal flow, and what layout adds

Before you write any layout CSS, the browser is already laying things out using normal flow: block elements (<p>, <section>, <article>) stack vertically at full width; inline elements (<a>, <span>) sit side by side within a line.

Normal flow is already responsive — a stack of full-width blocks works perfectly at 375px. Layout tools are for when you want something other than a stack: a row of nav links, a grid of cards.

The tool not to reach for is position: absolute, which takes an element out of flow and pins it to coordinates you picked. Coordinates you picked are correct at exactly one width.

Dimensioned placement vs constraint-driven placement

You can place every component by dimensioning it from the board origin — X 12.4, Y 30.1. It works, until the enclosure changes and every dimension is wrong at once. Constraint-driven placement instead declares relationships: these parts sit on one rail, equally spaced, with minimum clearance. Change the outline and the placement recomputes. Absolute positioning is the first approach; Flexbox and Grid are the second.

Flexbox: one dimension

Flexbox arranges children along a single axis — a row or a column. You turn it on for a container, and its direct children become flex items.

.site-nav ul {
  display: flex;
  gap: 1rem;
  list-style: none;
  padding: 0;
  margin: 0;
  flex-wrap: wrap;
}

Four properties do most of the work:

Property Effect
display: flex Children lay out in a row (the default direction)
gap Space between items — no margin arithmetic needed
justify-content Distribution along the axis: flex-start, center, space-between
align-items Alignment across the axis: center vertically centres a row

flex-wrap: wrap lets items drop onto a second line when they no longer fit, which keeps a nav bar from overflowing on a phone. Flexbox suits a nav bar, a row of buttons, a label beside a value — anything that is fundamentally a line of things.

Grid: two dimensions

CSS Grid is the strongest tool for two-dimensional layout: rows and columns at the same time, with items aligned in both directions. Where Flexbox arranges a line, Grid arranges a table of cells that you define.

.projects {
  display: grid;
  gap: 1rem;
  grid-template-columns: repeat(3, 1fr);
}

grid-template-columns declares the columns. repeat(3, 1fr) means three columns; fr is a fraction of the leftover space, so 1fr 1fr 1fr splits it evenly, and 2fr 1fr makes the first column twice as wide. Items flow into the cells in order, and new rows are created as needed.

The reason Grid beats Flexbox here is alignment across rows: in a grid, card 4 lines up under card 1 automatically, because they share a column. With wrapped flex items they only line up by luck.

Beads on a wire vs a muffin tin

Flexbox is beads on a single wire: you control spacing and order along that one wire. Grid is a muffin tin: the wells exist before the batter, in rows and columns, and everything you pour in lands aligned in both directions.

Media queries and fluid sizing

A media query applies a block of CSS only when a condition about the viewport holds:

@media (min-width: 40rem) {
  .projects {
    grid-template-columns: repeat(2, 1fr);
  }
}

Read it as: "when the viewport is at least 40rem wide, use two columns." Below that the rule does not exist and whatever you wrote outside the query still applies.

That ordering is mobile-first: write narrow-screen styles as your normal rules, then use min-width queries to add complexity as space appears. The alternative — designing wide and stripping things away with max-width queries — makes the smallest, slowest devices load the most rules.

Media queries need the viewport meta tag from Day 8. Without <meta name="viewport" content="width=device-width, initial-scale=1" />, a phone pretends to be about 980px wide and zooms out, so min-width: 40rem matches when it should not.

Media queries are the coarse tool. Reach first for fluid sizing, which needs no breakpoints:

img {
  max-width: 100%;
  height: auto;
}

body {
  max-width: 60rem;
  margin: 0 auto;
}

max-width: 100% means "never wider than your container" — one declaration that stops every image from causing horizontal scroll. And grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr)) tells the browser to fit as many columns of at least 16rem as it can: one column on a phone, three on a desktop, with no media query at all.

Walkthrough: responsive project cards

In index.html, wrap your project cards in a container:

<section>
  <h2>Projects</h2>
  <div class="projects">
    <article class="card">
      <h3>Pump controller</h3>
      <p>An STM32 board that logs runtime hours.</p>
    </article>
    <article class="card">
      <h3>Bench PSU monitor</h3>
      <p>Reads current and voltage over serial.</p>
    </article>
    <article class="card">
      <h3>Cable tester</h3>
      <p>Continuity checker for harnesses.</p>
    </article>
  </div>
</section>

Then add to styles.css:

img {
  max-width: 100%;
  height: auto;
}

.site-nav ul {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  list-style: none;
  padding: 0;
  margin: 0;
}

.projects {
  display: grid;
  gap: 1rem;
  grid-template-columns: 1fr;
}

@media (min-width: 40rem) {
  .projects {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (min-width: 60rem) {
  .projects {
    grid-template-columns: repeat(3, 1fr);
  }
}

Add class="site-nav" to your <nav>. Now drag your browser window narrow and wide: the cards go three, two, one, and the nav links wrap rather than overflowing.

Test at a real phone width

Open DevTools and toggle the device toolbar — Cmd+Shift+M on macOS, Ctrl+Shift+M on Windows and Linux. Set the width to 375. Then, in the Elements panel, click the small grid badge next to your .projects element: Chrome overlays the actual column lines. You are seeing the tracks, not guessing at them.

Your turn

  1. Add the .projects grid and the nav flex rule above, and confirm the three-to-one column behaviour by resizing.
  2. Replace both media queries with one fluid rule: grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));. Resize again, decide which version you prefer, and write down why — both are correct; having a reason is the point.
  3. At 375px in the device toolbar, scroll the page. There must be no horizontal scrollbar. If there is, find the too-wide element: a fixed px width, or an image without max-width: 100%.
  4. Check the nav at 375px. Links should wrap onto a second line, all still tappable.
  5. Confirm you used no position: absolute and no fixed pixel widths on anything holding text.
  6. Read the page at 375px and at desktop width and confirm the content order is identical. Layout may change; reading order should not.

You are done when

The page is usable at 375px and at desktop width, with no sideways scrolling at either, and you can say for each container whether it is Flexbox or Grid and why that one.

Pair mode, for the section you are least sure about

Pair programmer mode: you define one small task, review what comes back, and keep the judgement. Before accepting any suggestion, inspect the diff, run the checks — here, resize to 375px — and be able to explain the behaviour. Do not accept CSS you cannot read.

"Propose a minimal responsive layout. Do not use absolute positioning. Explain why Grid or Flexbox fits each section."

If the answer arrives with fixed pixel widths or absolute positioning, reject it and say so.

Common pitfalls

  • Missing viewport meta tag. The single most common reason a "responsive" site still looks zoomed-out on a phone. Check it is in every page's <head>.
  • Fixed pixel widths. width: 800px cannot fit a 375px screen. Use max-width instead, which sets a ceiling and lets the element shrink below it.
  • Testing only by resizing the desktop window. Useful, but the device toolbar at 375px is what reveals the overflow. Do both.
  • Using Grid for a nav bar or Flexbox for a card grid. Both will work. One dimension means Flexbox; alignment in rows and columns means Grid.

Verify it yourself

Open today's reference, MDN's CSS layout, and find its introduction to Flexbox and to Grid.

  1. MDN lists cases where Flexbox is the better choice and cases where Grid is. Find one example that contradicts a choice you made today, and decide whether to change it.
  2. Find MDN's explanation of the fr unit. Does it agree that fr distributes leftover space rather than total width? Test the difference by giving one card a long unbroken word.

Record both answers in notes/day-12.md, along with the breakpoint values you chose and why.

The hour

  1. 0–5 min Recall

    Without notes, state yesterday’s main idea and one unresolved question.

  2. 5–20 min Learn

    Read only the listed concept notes and official reference sections needed today.

  3. 20–48 min Build

    Make the project cards responsive: one column on narrow screens and multiple columns when space allows.

  4. 48–55 min Explain and verify

    Run the result, inspect evidence, and explain the data/control flow in your own words.

  5. 55–60 min Quiz and commit

    Complete the quiz, record one lesson, and commit the verified change when applicable.

What to hand in

Deliverable

A layout usable at 375px and desktop widths.

Working with AI today

AI as pair programmer

Define one small task, review the plan, inspect the diff, run checks, and explain every changed section.

Propose a minimal responsive layout. Do not use absolute positioning. Explain why Grid or Flexbox fits each section.

References

End-of-day quiz

Q1 Which tool is generally strongest for two-dimensional layouts?
Q2 Which result best proves today’s work is complete?
Q3 Before accepting an AI-generated code change, what should you do?

Explain-back gate

Pass the quiz above to unlock completion.

Quiz + explain-back checks required.