Frontend Development · Tutorial 3 of 5
CSS Flexbox vs Grid: which one, when
By the FUTEAC Team · 30 October 2026 · 10 min read · Beginner
In short
Flexbox lays things out in one direction — a row or a column. Grid lays things out in two — rows and columns together. Rule of thumb: a line of items (navbar, button row, card contents) is Flexbox; a two-dimensional area (gallery, dashboard, page skeleton) is Grid. Most real pages use both, each where it fits.
- Flexbox is one-dimensional. It arranges items along a single axis — a row or a column — and is brilliant at distributing space within that line.
- Grid is two-dimensional. It arranges items in rows *and* columns at once, so it controls the whole area, not just one line.
- The decision rule is about direction. One direction to manage → Flexbox. Two directions to manage → Grid.
- They compose. A Grid page skeleton with Flexbox navigation inside it is the normal, professional pattern — not a contradiction.
- This tutorial feeds the HTML & CSS Foundations course (/course/html-css-foundations) and the CSS Flexbox (/skill/css-flexbox) and CSS Grid (/skill/css-grid) skills.
Before you start
What is the actual difference between Flexbox and Grid?
Both are CSS layout systems, and both move boxes around — but they think about space differently.
Flexbox thinks in lines. You give it a container and a direction (row or column), and it distributes the items along that one axis: spreading them out, centering them, pushing some to the ends, wrapping them onto new lines. It is *content-first*: the items' sizes influence the layout, and Flexbox's job is to share the available space fairly along its line.
Grid thinks in areas. You define rows and columns up front — a 3-column gallery, a sidebar-plus-content page — and place items into that two-dimensional structure. It is *layout-first*: the grid exists before the items arrive, and Grid's job is to hold the whole area's shape.

That is the whole conceptual difference. Everything else in this tutorial is consequences of it.
When do I reach for Flexbox?
Reach for Flexbox when your items form a line: one row or one column, where the interesting question is how space is shared *along that line*.
A navigation bar. Logo on the left, links on the right, everything vertically centered:
.navbar {
display: flex;
justify-content: space-between; /* push logo left, links right */
align-items: center; /* center everything vertically */
padding: 12px 24px;
}
.nav-links {
display: flex;
gap: 20px;
list-style: none;
margin: 0;
padding: 0;
}Expected result: the logo sits at the left edge, the links sit at the right edge in a neat row with 20px gaps, and everything is vertically centered — three declarations doing the work that used to take floats and clearfix hacks.
The inside of a card. Title, description and button stacked in a column, with the button pinned to the bottom even when cards have different amounts of text:
.card {
display: flex;
flex-direction: column;
gap: 8px;
}
.card button {
margin-top: auto; /* pushes the button to the bottom of the card */
}Expected result: in a row of cards, every button lines up at the same height regardless of text length — margin-top: auto absorbs the leftover space in the column.
Centering one thing. The classic:
.center-me {
display: flex;
justify-content: center;
align-items: center;
}Flexbox's home territory, in short: navbars, button rows, form rows, card contents, toolbars, centering — components arranged in a line.
When do I reach for Grid?
Reach for Grid when you need to control rows and columns together: the interesting question is the shape of the whole area, not just one line.
A photo gallery. Three equal columns, and you do not care how many photos there are:
.gallery {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}Expected result: photos flow into three equal columns; add a seventh photo and it starts a new row automatically. No widths to calculate, no floats to clear.
A responsive gallery — the same idea, but the column count adapts to the screen:
.gallery {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
gap: 16px;
}Expected result: as many 220px-minimum columns as fit, each stretching to share leftover space. On a phone you get one column; on a desktop, four or five — one line of CSS, no media queries.
A page skeleton. Header across the top, sidebar plus content in the middle, 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;
}
.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.footer { grid-area: footer; }Expected result: the named areas draw the page like a floor plan — read grid-template-areas and you can *see* the layout. The sidebar is 220px, the content takes the rest, the middle row stretches to fill the viewport height.
Grid's home territory: galleries, card grids, dashboards, page skeletons, forms with aligned labels and fields — two-dimensional areas.
What is the 10-second decision rule?
Ask one question: how many directions am I managing?
- One direction — a row of items, a column of items, distributing space along a line → Flexbox.
- Two directions — rows *and* columns, an area with a shape → Grid.
Three refinements that save beginners hours:
- Wrapping does not make Flexbox two-dimensional.
flex-wrap: wraplets a row spill onto more rows, but Flexbox still thinks line by line — each row sizes itself independently. If your wrapped rows must align into columns (a true grid), that is Grid's job. - Simple does not mean Flexbox. A single row of three cards *sounds* one-dimensional, but if the cards must align into columns on every row as content grows, Grid's
repeat(3, 1fr)says what you mean and Flexbox's wrapping only approximates it. - When both fit, pick the simpler read. A navbar is Flexbox even though you *could* build it as a one-row grid — future readers of your CSS will thank you.
Can I use Flexbox and Grid together?
Yes — and you should. This is the normal professional pattern, not a contradiction: Grid for the area, Flexbox for the lines inside it.
The page skeleton above is Grid. The navbar inside its header is Flexbox. The gallery in the main area is Grid. Each card inside the gallery lays out its own title, text and button with Flexbox. Zoom out one more level and the whole arrangement is: Grid areas containing Flexbox lines containing content. That layering is how real stylesheets are organized, and it is exactly what the worked example below builds.
Worked example: a team page that uses both
Build a small team page: a grid of member cards, with Flexbox arranging each card's contents.
Step 1 — The HTML. One section holding several articles:
<section class="team">
<article class="member-card">
<h3>Ayesha Khan</h3>
<p class="role">Frontend Developer</p>
<p>Builds interfaces with HTML, CSS and JavaScript.</p>
<button>View profile</button>
</article>
<article class="member-card">
<h3>Bilal Ahmed</h3>
<p class="role">Backend Developer</p>
<p>Designs APIs and databases. Also writes documentation nobody reads, then rewrites it.</p>
<button>View profile</button>
</article>
<article class="member-card">
<h3>Chen Wei</h3>
<p class="role">UI Designer</p>
<p>Turns rough ideas into screens in Figma.</p>
<button>View profile</button>
</article>
</section>Step 2 — Grid for the area. The cards form a responsive grid:
.team {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
gap: 20px;
padding: 24px;
}Step 3 — Flexbox for the lines inside. Each card stacks its contents in a column, with the button pinned to the bottom:
.member-card {
display: flex;
flex-direction: column;
gap: 8px;
padding: 20px;
border: 1px solid #e5e7eb;
border-radius: 8px;
}
.member-card .role {
color: #6b7280;
margin: 0;
}
.member-card button {
margin-top: auto; /* bottom-aligns the button across all cards */
align-self: flex-start;
padding: 8px 16px;
}Expected result: a responsive grid of cards — one column on a phone, three on a desktop. Inside every card the title, role, bio and button stack neatly, and every "View profile" button sits at the same height even though Bilal's bio is longer than the others'. Grid decided the area; Flexbox decided each line. That division of labour is the entire tutorial in one page.
Try it yourself
Take any page you have built (or the course card from the box-model tutorial) and rebuild its layout twice: once with everything in Flexbox, once with everything in Grid. Notice where each one fights you — the Flexbox version will strain at the two-dimensional parts, the Grid version will feel verbose at the one-dimensional parts. Then build it a third time with Grid for the areas and Flexbox for the lines. Keep the third version; that is the pattern.
Common mistakes
- Using Flexbox with wrapping as a fake grid. Wrapped flex rows size independently, so columns drift out of alignment as content varies. If you need columns, use Grid.
- Using Grid for a simple line. A one-row, three-item toolbar does not need
grid-template-columns—display: flexwith a gap says it in one line. - Forgetting
flex-wrap. A flex row with many items overflows its container on narrow screens instead of wrapping. If the row must collapse gracefully, addflex-wrap: wrap— or reconsider Grid. - Mixing up the two axes. In Flexbox,
justify-contentworks along the main axis (the direction you chose) andalign-itemsacross it. In arowcontainer, that meansjustify-contentmoves things horizontally. Getting this backwards is the single most common Flexbox confusion. - Fixed column counts with no responsive plan.
repeat(3, 1fr)on a phone gives three crushed columns. Preferrepeat(auto-fit, minmax(240px, 1fr))so the grid degrades to fewer columns instead of narrower ones.
Frequently asked questions
Which should I learn first, Flexbox or Grid?
Flexbox. You will use it in almost every component from day one — navbars, cards, forms — while Grid pays off once you start building whole page areas. Learn Flexbox deeply, then add Grid; the course teaches them in exactly that order.
Does Grid replace Flexbox?
No. They solve different problems — one axis versus two — and the CSS specifications were designed as companions. Asking which replaces the other is like asking whether a saw replaces a hammer.
Do I still need media queries if Grid is responsive?
Sometimes. auto-fit with minmax() handles the common case — columns that collapse as space shrinks — with no media queries at all. But bigger layout changes (sidebar moving below content on phones, the page skeleton re-stacking) still need a media query that redefines the grid areas. That is the next tutorial in this series.
What about Tailwind or Bootstrap — do they change the answer?
No. Utility frameworks are shorthands for the same two systems (flex, grid, grid-cols-3 are Flexbox and Grid underneath). Learn the underlying rule first; the shorthand then reads as obvious instead of magical.
Where do Flexbox and Grid sit in the Frontend Developer roadmap?
They are the core of the "Layout and Responsive Design" module, right after the box model and before responsive design with media queries. The roadmap's layout project — rebuilding a real page's skeleton — is where you practice the Grid-areas-plus-Flexbox-lines pattern from this tutorial. ---
Follow the Frontend Developer Roadmap
Build modern, responsive websites and web apps with HTML, CSS, JavaScript and React. Free, step by step, at your pace.
View the Roadmap