AniUI Academy

CSS Grid in Practice

A full-page header/sidebar/main/footer layout with grid-template-areas, a responsive card grid using repeat(auto-fit, minmax()), and when to reach for grid versus flexbox.

9 min read

The previous lesson introduced grid's individual tools. This lesson builds two real layouts you'll reuse constantly — a whole-page skeleton and a responsive card grid that needs no media queries — and then draws a clear line between when to reach for grid versus flexbox.

A full-page layout with grid-template-areas

This is the shape almost every content-heavy page eventually needs: a header across the top, a sidebar down one side, a main content area, and a footer across the bottom.

.page {
  display: grid;
  grid-template-columns: 220px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "sidebar main"
    "footer footer";
  min-height: 100vh;
  gap: 1rem;
}
 
.header  { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main    { grid-area: main; }
.footer  { grid-area: footer; }
<div class="page">
  <header class="header">Site header</header>
  <nav class="sidebar">Sidebar navigation</nav>
  <main class="main">Page content</main>
  <footer class="footer">Footer</footer>
</div>

Reading the grid-template-areas value tells you the whole page's shape at a glance, without mentally tracing line numbers: header spans the full width on its own row, sidebar and main share the middle row, footer spans the full width again. min-height: 100vh makes the whole layout at least as tall as the viewport, so the footer doesn't ride up against short content.

A responsive card grid with auto-fit and minmax()

This single line replaces what used to take several media queries' worth of manual breakpoints:

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 1.5rem;
}

Breaking down exactly what each piece does:

  • minmax(200px, 1fr) defines one track's size range: never smaller than 200px, but allowed to grow up to 1fr — an equal share of whatever space is left once the minimum widths are satisfied.
  • repeat(auto-fit, ...) repeats that track definition as many times as will actually fit in the container's current width, given each repetition needs at least 200px. On a wide screen that might fit five columns; on a narrow one, maybe one or two — recalculated automatically as the container resizes, with no explicit breakpoint written anywhere.
  • Because the maximum in minmax is 1fr, whatever columns do fit also stretch to fill any leftover width evenly, so cards don't leave an awkward half-empty column at the edge.

The result: as the container narrows, columns don't shrink below 200px — instead, the grid drops a column entirely and redistributes the width among the ones that remain. That's the entire responsive behaviour, and it comes from one declaration, not a chain of @media rules each hand-picking a column count for a specific width.

Grid versus flexbox: the real rule of thumb

Both can build layouts, and there's real overlap in what each one can do, but the well-established way to decide which to reach for is about dimensionality:

  • Grid is for two-dimensional layout — when you need to coordinate rows and columns together, as one structure. A page skeleton, a card grid, anything where both the horizontal and vertical arrangement matter at once.
  • Flexbox is for one-dimensional layout — a single row or a single column of items, where you're really only reasoning about one axis at a time. A navbar, a button group, a list of tags.

In practice, real pages use both together, and that's not a compromise — it's the idiomatic way to build with either tool. Grid handles the page's overall skeleton (the header/sidebar/main/footer shape above), and flexbox handles the one-dimensional arrangements inside individual components sitting within that skeleton — the navbar inside the header, the row of buttons inside a card, the tag list inside the sidebar. Reaching for grid to center one row of icons, or reaching for flexbox to coordinate a whole page's rows and columns, both work against the tool's grain; each one is at its best solving the dimensionality it was built for.

Try it yourself

A full page skeleton built with grid-template-areas, and beneath it a responsive card grid using repeat(auto-fit, minmax(180px, 1fr)) — resize your browser window (or shrink the Playground) to watch the column count recalculate with no media query anywhere in the CSS.

Try it yourself
Loading playground...

What to remember

  • grid-template-areas names a full page's regions in ASCII-art form, and grid-area places each child into the region it belongs to.
  • repeat(auto-fit, minmax(200px, 1fr)) fits as many tracks as will satisfy the minimum width, then stretches them to fill any leftover space — one line replacing many hand-picked breakpoints.
  • Grid is for two-dimensional layout (rows and columns together); flexbox is for one-dimensional layout (a single row or column).
  • Real pages typically use both: grid for the page skeleton, flexbox for the one-dimensional components living inside it.

Check yourself

4 questions · pass 3/4 to unlock Positioning

up to 50
  1. 1.In repeat(auto-fit, minmax(200px, 1fr)), what does auto-fit actually control?

  2. 2.What does the 1fr in minmax(200px, 1fr) do once columns are placed?

  3. 3.What is the well-established rule of thumb for choosing grid versus flexbox?

  4. 4.In a typical real page, how do grid and flexbox usually coexist?

4 left to answer