Topic #04Foundational20 min read

Flexbox & Grid Layout

Modern CSS layout end to end: the flex container & item model, main/cross axis, every flex property, then CSS Grid's tracks, lines, areas, auto-fill/minmax, and exactly when to reach for each.

#css#flexbox#grid#layout#responsive#alignment#fundamentals

Why layout modules exist. Before Flexbox and Grid, developers centered boxes and built columns with float, display: inline-block, table hacks, and absolute positioning — fragile techniques that fought the browser. Flexbox (2015) and Grid (2017) are purpose-built layout engines. The rule of thumb: Flexbox for one dimension (a row or a column), Grid for two dimensions (rows and columns at once). They aren't rivals — you nest them constantly: Grid for the page shell, Flexbox inside each region.

Flexbox: the container/item model. You turn an element into a flex container with display: flex. Its direct children automatically become flex items and lay out along a single axis. Nothing else needs display — the magic is on the parent. Everything in Flexbox is described in terms of two axes, so get those straight first.

The two axes (the key mental model). The main axis is the direction items flow, set by flex-direction (default row = left→right). The cross axis is perpendicular to it. justify-content aligns items along the main axis; align-items aligns them along the cross axis. Flip flex-direction to column and the axes swap — main becomes vertical — which trips up beginners constantly. When alignment 'goes the wrong way,' check which axis is which.

Container properties (set on the parent). flex-direction (row | row-reverse | column | column-reverse) — the main axis. flex-wrap (nowrap | wrap) — whether items overflow or wrap to new lines; flex-flow is shorthand for both. justify-content (flex-start | center | flex-end | space-between | space-around | space-evenly) — main-axis distribution. align-items (stretch | flex-start | center | flex-end | baseline) — cross-axis alignment of each line. align-content — spacing between wrapped lines (only matters with multiple lines). gap — space between items (use this, not margins).

Item properties (set on the children). flex-grow (how much a spare space an item soaks up; default 0 = don't grow). flex-shrink (how readily it shrinks below its base size; default 1). flex-basis (the item's starting size before grow/shrink — auto uses its content/width). The shorthand flex: <grow> <shrink> <basis> bundles all three: flex: 1 means 1 1 0 (grow equally from zero — equal-width columns); flex: 0 0 240px means a fixed 240px sidebar that never grows or shrinks. align-self overrides align-items for one item; order reorders items visually without touching the HTML.

Centering — the thing everyone Googles. Perfectly centering a box is now three lines: display: flex; justify-content: center; align-items: center;. That centers on both axes regardless of the child's size. This single pattern replaced a decade of margin: auto / transform: translate(-50%,-50%) tricks.

CSS Grid: two dimensions at once. display: grid makes a grid container; you then define tracks (columns and rows) with grid-template-columns and grid-template-rows. Between tracks are grid lines (numbered from 1). Items are placed into cells, or span multiple cells to form an area. Unlike Flexbox (content-driven, one axis), Grid is layout-driven: you define the structure up front and drop content into it.

Defining tracks & the fr unit. grid-template-columns: 200px 1fr 1fr makes a fixed 200px column then two flexible columns. fr means 'one fraction of the leftover space' — 1fr 1fr splits remaining space evenly; 2fr 1fr gives the first twice as much. repeat(3, 1fr) is shorthand for three equal columns. minmax(min, max) bounds a track: minmax(200px, 1fr) never shrinks below 200px but grows to fill. Use gap (or row-gap/column-gap) for gutters.

The responsive grid with no media queries. The famous one-liner: grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)). The browser fits as many 240px-min tracks as the container allows, then stretches them to fill — cards reflow from 4 columns to 1 as the screen narrows, with zero breakpoints. auto-fit is the sibling: identical, except it collapses empty tracks so the existing items stretch to fill the whole row. Use auto-fill to keep the grid slots, auto-fit to stretch content edge-to-edge.

Placing items: lines, span, and areas. Place an item by line number: grid-column: 1 / 3 (from line 1 to line 3 = spans 2 columns), or grid-column: span 2. For readable layouts, name regions with grid-template-areas: draw the layout as ASCII strings on the container, then assign each child a grid-area name. This makes a header/sidebar/main/footer shell self-documenting and trivial to rearrange at breakpoints.

Alignment in Grid. Grid has the same alignment vocabulary as Flexbox, doubled for two axes: justify-items/align-items align content within each cell (inline / block axis), and justify-content/align-content align the whole grid within the container when tracks don't fill it. place-items: center is the shorthand to center content in every cell.

Flexbox vs Grid — how to choose. Ask: do I control one axis or two? One row/column where item sizes flow from content (toolbar, tag list, button group, nav) → Flexbox. A defined 2D structure (page shell, dashboard, image gallery, form grid) → Grid. When in doubt: if you're writing flex-direction and thinking about a single line of items, it's Flex; if you're drawing rows and columns, it's Grid. Real apps use both — Grid outside, Flex inside cells.

Common gotchas. (1) Flex/Grid properties only affect direct children — a wrapper <div> breaks the relationship. (2) justify-content vs align-items confusion comes from forgetting the axis flips with flex-direction. (3) flex: 1 on items includes flex-basis: 0, so items size purely by grow ratio, ignoring content width — use flex: 1 1 auto to respect content. (4) A flex item with long content can overflow because its default min-width is auto; fix with min-width: 0. (5) gap in Flexbox is well-supported now — stop using margin hacks.

The mental model (memorise this). Flexbox = one axis, content-first, container sets direction + distribution, items grow/shrink/basis. Grid = two axes, layout-first, container defines tracks/areas, items placed onto lines. justify-* = main/inline axis, align-* = cross/block axis. gap for spacing everywhere. Reach for Grid to structure the page, Flexbox to arrange things within it.

Backend Analogy

Think of Flexbox like a single-column processing pipeline where each stage (item) can be weighted to take a share of throughput — `flex-grow` is the weight in a weighted round-robin, `flex-basis` the reserved baseline capacity. Grid is more like defining a fixed schema / table layout up front (columns and rows declared, cells addressed by coordinate) and then binding records into it — `grid-template-areas` is the declarative mapping, like a layout config file, versus Flexbox's imperative 'flow them in order.'

Key Insights
  • Flexbox = one dimension (a row OR a column); Grid = two dimensions (rows AND columns). They nest: Grid for the shell, Flexbox inside.
  • Flex properties split into container props (flex-direction, justify-content, align-items, flex-wrap, gap) and item props (flex-grow/shrink/basis, align-self, order).
  • justify-content aligns along the MAIN axis; align-items aligns along the CROSS axis. The axes swap when flex-direction is column.
  • flex: 1 means 1 1 0 (grow equally from zero → equal columns); flex: 0 0 240px is a fixed non-flexing track.
  • Center anything: display:flex; justify-content:center; align-items:center. Three lines, both axes.
  • The fr unit is a fraction of leftover space; repeat() and minmax() build flexible tracks.
  • repeat(auto-fill, minmax(240px, 1fr)) = responsive card grid with zero media queries. auto-fit collapses empty tracks to stretch content.
  • Place grid items by line number (grid-column: 1 / 3) or name regions with grid-template-areas for self-documenting layouts.
  • Flex/Grid properties only affect DIRECT children — an extra wrapper div breaks them.
  • gap works in both Flexbox and Grid — prefer it over margins for inter-item spacing.

Worked Code

Flexbox: container + item properties explained
CSS
/* CONTAINER — turns children into flex items along the main axis */
.toolbar {
  display: flex;
  flex-direction: row;          /* main axis = horizontal (default) */
  justify-content: space-between; /* main-axis distribution */
  align-items: center;          /* cross-axis alignment */
  flex-wrap: wrap;              /* allow items to wrap to new lines */
  gap: 12px;                    /* space between items (not margins) */
}

/* ITEMS — control how each child flexes */
.logo    { flex: 0 0 auto; }    /* don't grow/shrink: natural size */
.search  { flex: 1 1 auto; }    /* grow to fill leftover space */
.avatar  { align-self: flex-end; order: 99; } /* override + reorder */

/* Equal-width columns: every item grows equally from a 0 basis */
.cols > * { flex: 1; }          /* == flex: 1 1 0 */
Perfect centering (both axes)
CSS
/* The pattern that replaced a decade of hacks */
.center {
  display: flex;
  justify-content: center;  /* main axis  */
  align-items: center;      /* cross axis */
  min-height: 100vh;
}

/* Grid can do it in two lines with place-items */
.center-grid {
  display: grid;
  place-items: center;      /* = justify-items + align-items */
  min-height: 100vh;
}
Grid: tracks, fr, minmax & responsive auto-fill
CSS
/* App shell: fixed sidebar + fluid content, full height */
.app-shell {
  display: grid;
  grid-template-columns: 240px 1fr;  /* fixed | flexible */
  grid-template-rows: auto 1fr auto;  /* header | body | footer */
  gap: 16px;
  min-height: 100vh;
}

/* Responsive card grid — NO media queries needed */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 16px;
}
/* auto-fit instead of auto-fill stretches items to fill empty tracks */

/* Explicit placement by grid lines */
.feature { grid-column: 1 / 3; }   /* span from line 1 to 3 */
.tall    { grid-row: span 2; }     /* span two rows */
Grid template areas — a self-documenting page layout
CSS
.page {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header  header"
    "sidebar main"
    "footer  footer";
  min-height: 100vh;
  gap: 12px;
}
.page > header  { grid-area: header;  }
.page > nav     { grid-area: sidebar; }
.page > main    { grid-area: main;    }
.page > footer  { grid-area: footer;  }

/* Rearrange for mobile by redrawing the map — no markup change */
@media (max-width: 640px) {
  .page {
    grid-template-columns: 1fr;
    grid-template-areas: "header" "main" "sidebar" "footer";
  }
}

Try It Live

Edit the code and press Run — it executes safely in a sandboxed iframe. Use the Console tab for log output.

Flexbox alignment + a responsive auto-fill grid, live

Interview-Ready Q&A

Flexbox for one-dimensional layouts where content drives sizing — toolbars, button rows, tag lists, navs. Grid for two-dimensional layouts where you define structure up front — page shells, dashboards, galleries. They compose: Grid for the outer shell, Flexbox within cells. Quick test: one axis → Flex, rows and columns together → Grid.

Things to Remember
  • 1Flexbox = 1D (row or column). Grid = 2D (rows and columns). They nest.
  • 2Container props vs item props — the layout magic lives on the parent.
  • 3justify-content = main axis, align-items = cross axis; axes swap with flex-direction: column.
  • 4flex: 1 → 1 1 0 (equal columns); flex: 0 0 Npx → fixed track.
  • 5Center anything: display:flex; justify-content:center; align-items:center (or Grid place-items:center).
  • 6fr = a fraction of leftover space; repeat() + minmax() build flexible tracks.
  • 7repeat(auto-fill, minmax(MIN,1fr)) = responsive grid, no breakpoints. auto-fit stretches; auto-fill keeps slots.
  • 8Name regions with grid-template-areas for readable, easily-rearranged layouts.
  • 9Only DIRECT children are flex/grid items — watch for stray wrappers.
  • 10Use gap for spacing in both; fix overflow with min-width: 0 on flex items.

References & Further Reading