Skip to main content
{/}codefunc
CSS & DesignJuly 7, 2026 · 9 min read

CSS Flexbox and Grid: When to Use Each and How They Work Together

A practical guide to modern CSS layout — flexbox for one-dimensional alignment, grid for two-dimensional structure, and patterns for combining them in production components.

By codefunc

cssflexboxgridlayoutresponsivedesign

Layout used to require floats, clearfixes, and inline-block hacks. Flexbox and Grid replaced all of that with purpose-built layout systems. Flexbox handles one-dimensional layouts — rows or columns. Grid handles two-dimensional layouts — rows and columns together. Understanding when to use each (and when to combine them) is the difference between CSS that fights you and CSS that works.

Bottom line: Use flexbox when items flow in one direction and you need alignment or distribution. Use grid when you need explicit rows and columns or want content to define track sizes. Most real UIs combine both: grid for page structure, flexbox for component internals.

The mental model

System Dimension Best for
Flexbox One (row or column) Navigation, button groups, card internals, centering
Grid Two (rows + columns) Page layouts, dashboards, galleries, form layouts

Flexbox is content-driven — items determine their size, and the container distributes space. Grid is layout-driven — you define tracks, and items fill them.

Flexbox fundamentals

The flex container

.container {
  display: flex;
  flex-direction: row;      /* main axis: horizontal */
  justify-content: center;  /* align along main axis */
  align-items: center;      /* align along cross axis */
  gap: 1rem;                /* space between items */
}

Adding display: flex makes children become flex items. They flow along the main axis (default: horizontal) and align along the cross axis (default: vertical).

Main axis vs cross axis

Property Axis Controls
flex-direction Defines main row, column, row-reverse, column-reverse
justify-content Main Distribution of items
align-items Cross Alignment of items
align-content Cross Alignment of wrapped lines

justify-content options

.container {
  justify-content: flex-start;    /* pack at start */
  justify-content: flex-end;      /* pack at end */
  justify-content: center;        /* center items */
  justify-content: space-between; /* equal space between, none at edges */
  justify-content: space-around;  /* equal space around each item */
  justify-content: space-evenly;  /* equal space everywhere */
}

align-items options

.container {
  align-items: stretch;     /* fill cross axis (default) */
  align-items: flex-start;  /* align to start */
  align-items: flex-end;    /* align to end */
  align-items: center;      /* center on cross axis */
  align-items: baseline;    /* align text baselines */
}

Flex item properties

Property Effect
flex-grow How much item grows relative to siblings
flex-shrink How much item shrinks when space is tight
flex-basis Initial size before growing/shrinking
flex Shorthand: flex: grow shrink basis
align-self Override align-items for one item
order Change visual order without changing DOM

Common flex patterns

Centering (the classic)

.center-everything {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

Navigation bar

.navbar {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 1rem;
}

.nav-links {
  display: flex;
  gap: 1.5rem;
}

Card with footer at bottom

.card {
  display: flex;
  flex-direction: column;
  height: 100%;
}

.card-body {
  flex: 1; /* grow to fill space */
}

.card-footer {
  margin-top: auto; /* push to bottom */
}

Input with button

.input-group {
  display: flex;
}

.input-group input {
  flex: 1;          /* take remaining space */
  min-width: 0;     /* allow shrinking below content size */
}

.input-group button {
  flex-shrink: 0;   /* don't shrink */
}

Flexbox gotchas

Issue Cause Fix
Item won't shrink Content sets minimum width Add min-width: 0
Text overflows Flex items don't wrap text by default Add overflow-wrap: break-word
Image stretches align-items: stretch is default Add align-items: flex-start or set image align-self
Gap not working Older browsers Check caniuse; use margin fallback

Grid fundamentals

The grid container

.container {
  display: grid;
  grid-template-columns: repeat(3, 1fr); /* 3 equal columns */
  grid-template-rows: auto 1fr auto;     /* header, content, footer */
  gap: 1rem;
}

Defining tracks

/* Fixed sizes */
grid-template-columns: 200px 200px 200px;

/* Fractional units (flexible) */
grid-template-columns: 1fr 2fr 1fr;  /* middle column is 2x wider */

/* Repeat function */
grid-template-columns: repeat(4, 1fr);

/* Mixed */
grid-template-columns: 250px 1fr 1fr;

/* Auto-fit for responsive grids */
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));

The fr unit

fr means "fraction of available space." After fixed-size tracks are calculated, remaining space is divided by total fr values.

grid-template-columns: 200px 1fr 2fr;
/* 200px fixed, then 1/3 of remainder, then 2/3 of remainder */

Placing items

Grid items automatically fill cells in order. For explicit placement:

.item {
  grid-column: 1 / 3;    /* span columns 1-2 */
  grid-row: 2 / 4;       /* span rows 2-3 */
}

/* Shorthand */
.item {
  grid-area: 2 / 1 / 4 / 3;  /* row-start / col-start / row-end / col-end */
}

/* Named lines */
.item {
  grid-column: content-start / content-end;
}

Named grid areas

.layout {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar main aside"
    "footer footer footer";
  grid-template-columns: 200px 1fr 200px;
  grid-template-rows: auto 1fr auto;
}

.header { grid-area: header; }
.sidebar { grid-area: sidebar; }
.main { grid-area: main; }
.aside { grid-area: aside; }
.footer { grid-area: footer; }

Responsive grid patterns

Auto-fill cards

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

Cards fill available space with minimum 280px width. No media queries needed.

auto-fill vs auto-fit

Keyword Behavior
auto-fill Creates empty tracks if space remains
auto-fit Collapses empty tracks, items stretch

Use auto-fit when you want items to grow into empty space. Use auto-fill when you want consistent track sizes.

Common grid patterns

Holy grail layout

.page {
  display: grid;
  grid-template-rows: auto 1fr auto;
  min-height: 100vh;
}

header { /* auto height */ }
main { /* fills remaining space */ }
footer { /* auto height */ }

Dashboard with sidebar

.dashboard {
  display: grid;
  grid-template-columns: 250px 1fr;
  grid-template-rows: auto 1fr;
  min-height: 100vh;
}

.sidebar {
  grid-row: 1 / -1; /* span all rows */
}

Image gallery with featured item

.gallery {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 0.5rem;
}

.featured {
  grid-column: span 2;
  grid-row: span 2;
}

Grid alignment

.container {
  /* Align items within their cells */
  justify-items: center;  /* horizontal */
  align-items: center;    /* vertical */
  place-items: center;    /* shorthand */
  
  /* Align the grid within the container */
  justify-content: center;  /* horizontal */
  align-content: center;    /* vertical */
  place-content: center;    /* shorthand */
}

.item {
  /* Override for single item */
  justify-self: end;
  align-self: start;
}

When to use flexbox vs grid

Scenario Use
Navbar with logo + links + actions Flexbox
Card grid with responsive columns Grid
Button group Flexbox
Form with aligned labels and inputs Grid
Centering a single element Flexbox
Page-level layout (header, main, footer) Grid
Distributing space between items Flexbox
Overlapping elements Grid
Unknown number of items in a row Flexbox
Known column structure Grid

The practical answer

Most UIs need both:

/* Grid for page structure */
.page {
  display: grid;
  grid-template-rows: auto 1fr auto;
}

/* Flexbox inside header */
.header {
  display: flex;
  justify-content: space-between;
  align-items: center;
}

/* Grid for main content cards */
.content {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
}

/* Flexbox inside each card */
.card {
  display: flex;
  flex-direction: column;
}

Combining flexbox and grid

Card component pattern

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

.card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: 0.5rem;
  overflow: hidden;
}

.card-image {
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

.card-content {
  flex: 1;
  display: flex;
  flex-direction: column;
  padding: 1rem;
}

.card-title {
  font-weight: 600;
}

.card-description {
  flex: 1;  /* push footer down */
  color: var(--muted);
}

.card-footer {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: auto;
}

Form layout pattern

.form {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1rem 1.5rem;
  align-items: center;
}

.form label {
  text-align: right;
}

.form .full-width {
  grid-column: 1 / -1;
}

.form .button-group {
  grid-column: 2;
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
}

Responsive layout without media queries

Modern CSS layout reduces media query needs:

.responsive-section {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 400px), 1fr));
  gap: clamp(1rem, 3vw, 2rem);
  padding: clamp(1rem, 5vw, 3rem);
}

The min(100%, 400px) pattern prevents overflow on small screens while maintaining minimum width on larger ones.

Testing layouts

Experiment with flexbox and grid properties interactively using the Flexbox & Grid Playground. Adjust direction, alignment, gap, and template columns to see behavior before writing component code.

For fluid spacing values, calculate responsive clamp() values with the CSS Clamp Calculator.

Browser DevTools for layout

Modern DevTools visualize both systems:

  1. Flexbox overlay — shows main/cross axes, item sizes
  2. Grid overlay — shows track lines, areas, gaps
  3. Computed tab — shows resolved values

In Chrome/Edge: click the flex or grid badge next to elements in the Elements panel.

Common mistakes

Mistake Problem Fix
Grid for simple row Overkill Use flexbox
Flexbox for 2D layout Fighting the model Use grid
Fixed pixel columns Not responsive Use fr, minmax(), auto-fit
Forgetting gap Using margin on items Gap is cleaner
Nested grids everywhere Complex debugging Flatten where possible
height: 100% without chain Doesn't work Grid with 1fr row

Use these codefunc tools alongside this guide:

Practical takeaway

Flexbox aligns and distributes items in one dimension. Grid creates explicit two-dimensional structures. Use flexbox for component internals — navbars, button groups, card content. Use grid for page layouts and content grids. Combine them: grid for structure, flexbox for alignment within cells. Test with DevTools overlays. Default to auto-fit with minmax() for responsive grids without breakpoints.

Sources

Try it on codefunc

Related articles

3

Search tools

Find a developer tool