Frontend / CSS / 06_flexbox_and_grid.md

Flexbox and Grid

Updated 6 interview angles 4 min read source
On this page8
  1. Flexbox: one axis, content-driven
  2. Grid: two axes, container-driven
  3. Choosing
  4. Centring, finally solved
  5. gap replaced margin hacks
  6. What is next
  7. Related
  8. Interview angle

Flexbox and Grid

One question decides between them: is the layout one-dimensional or two? Flexbox distributes items along a single axis; Grid places them into rows and columns that exist whether or not anything fills them.

Flexbox: one axis, content-driven

css
.toolbar {
  display: flex;
  align-items: center;      /* cross axis */
  justify-content: space-between;   /* main axis */
  gap: 1rem;
}

justify-* works on the main axis and align-* on the cross axis. Setting flex-direction: column swaps which is which — that is the single most common source of “why is align-items doing nothing”.

The shorthand is where the real behaviour lives:

css
.item { flex: 1; }          /* = 1 1 0%   grow, shrink, basis */
.item { flex: auto; }       /* = 1 1 auto — starts from content size */
.item { flex: none; }       /* = 0 0 auto — never resizes */

flex: 1 versus flex: auto is a real interview question. With flex: 1 the basis is 0%, so items share the container equally regardless of content. With flex: auto the basis is the content width, so items keep their natural proportions and only share the leftover space.

Gotcha: a flex item will not shrink below its content’s minimum size, because min-width defaults to auto. That is why a long string or a <pre> blows out a flex layout, and why min-width: 0 is the fix that looks like a hack and is not.

Grid: two axes, container-driven

css
.layout {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 1rem;
}

That one line is responsive without a media query: as many 240px-minimum columns as fit, sharing the space equally. auto-fill leaves empty tracks; auto-fit collapses them so the existing items stretch — the difference shows only when there are fewer items than columns.

Named areas make a page layout readable:

css
.page {
  display: grid;
  grid-template-areas:
    "header header"
    "nav    main"
    "footer footer";
  grid-template-columns: 200px 1fr;
}
.page > nav { grid-area: nav; }

fr is a unit only Grid has: a fraction of the remaining space, after fixed tracks and gaps are subtracted. 1fr is not 50% — percentages do not account for the gap, which is why a two-column 50% 50% layout with a gap overflows and 1fr 1fr does not.

Choosing

Situation Use
A row of buttons, a nav bar flex
Content decides the sizes flex
Wrapping cards, equal columns grid
A page skeleton grid
Overlapping items grid

Grid for the page, flex for the components is the usual split, and they nest freely — a grid cell containing a flex row is normal.

Grid can also overlap, which flex cannot: place two items in the same grid-area and they stack, which is a cleaner way to layer a caption over an image than absolute positioning.

Centring, finally solved

css
.parent { display: grid; place-items: center; }

Two lines, any content, any size, both axes. The older answers — absolute positioning with transforms, table-cell, flex with justify and align — all still work and none are shorter.

For the “centre one child but not the others” case:

css
.parent { display: grid; }
.child  { place-self: center; }

gap replaced margin hacks

gap works in flex, grid and multi-column, and it applies only between items — no trailing margin on the last one, no :last-child { margin: 0 } override. Any layout code still using margin-right for spacing between flex items predates it.

What is next

Subgrid lets a nested grid align to its parent’s tracks, which solves card layouts where headers and footers must line up across cards of different content lengths — the classic failure of nested grids.

Container queries let a component respond to its own width rather than the viewport’s, so the same card works in a sidebar and a full-width row. Both are in Container Queries and Subgrid, and together they are the biggest layout shift since Grid itself.

Interview angle 6

  • “Flexbox or Grid?” - one dimension or two. Flex distributes items along a single axis and is content-driven; Grid defines rows and columns that exist regardless of content. Grid for the page skeleton, flex for the components inside it, nested freely.
  • “What’s the difference between flex: 1 and flex: auto?” - the basis. flex: 1 is 1 1 0%, so items share the container equally whatever their content. flex: auto is 1 1 auto, so items keep their natural size and share only the leftover space.
  • “A long string breaks my flex layout. Why?” - a flex item’s min-width defaults to auto, so it refuses to shrink below its content’s minimum. min-width: 0 on the item is the fix, and it is a genuine part of the spec rather than a hack.
  • “How do you build a responsive card grid without media queries?” - grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)). auto-fit instead of auto-fill collapses empty tracks so existing items stretch to fill.
  • “Why use 1fr rather than 50%?” - fr divides the space remaining after fixed tracks and gaps. Percentages ignore the gap, so 50% 50% plus a gap overflows the container while 1fr 1fr does not.
  • “How do you centre something?” - display: grid; place-items: center on the parent. Two lines, both axes, any content size. Use place-self on the child if only one item should be centred.