DEV Community

Alex Chen
Alex Chen

Posted on

CSS Flexbox & Grid: The Layout Guide I Wish I Had (2026)

CSS Flexbox & Grid: The Layout Guide I Wish I Had (2026)

Stop fighting with CSS layouts. Once you understand these two systems, everything clicks.

The Big Picture

Before 2017: Floats, tables, absolute positioning → painful
2017+: Flexbox + Grid → layout is actually easy now

When to use which:
→ Flexbox: ONE-dimensional layout (row OR column)
→ Grid: TWO-dimensional layout (rows AND columns)

Most layouts use BOTH together.
Enter fullscreen mode Exit fullscreen mode

Flexbox Fundamentals

Core Concepts

.container {
  display: flex;

  /* Main axis direction */
  flex-direction: row;        /* Default: left to right */
  flex-direction: row-reverse; /* Right to left */
  flex-direction: column;     /* Top to bottom */
  flex-direction: column-reverse; /* Bottom to top */

  /* Wrapping behavior */
  flex-wrap: nowrap;          /* Default: don't wrap, shrink items */
  flex-wrap: wrap;            /* Wrap to next line when needed */
  flex-wrap: wrap-reverse;    /* Wrap upward */

  /* Shorthand for direction + wrap */
  flex-flow: row wrap;

  /* Main axis alignment */
  justify-content: flex-start;   /* Default: pack to start */
  justify-content: center;       /* Center horizontally */
  justify-content: flex-end;     /* Pack to end */
  justify-content: space-between; /* Equal space BETWEEN items */
  justify-content: space-around;  /* Equal space AROUND each item */
  justify-content: space-evenly;  /* Equal space everywhere */

  /* Cross axis alignment */
  align-items: stretch;        /* Default: stretch to fill container */
  align-items: flex-start;     /* Align to cross-axis start */
  align-items: center;         /* Center vertically */
  align-items: flex-end;       /* Align to cross-axis end */
  align-items: baseline;       /* Align text baselines */

  /* Gap between items */
  gap: 16px;                   /* Row and column gap */
  row-gap: 8px;
  column-gap: 16px;
}

.item {
  /* Item-level control */
  flex-grow: 0;      /* Default: don't grow to fill space */
  flex-shrink: 1;    /* Default: can shrink if needed */
  flex-basis: auto;  /* Default initial size */

  /* Shorthand: grow shrink basis */
  flex: 1;           /* grow=1, shrink=1, basis=0% → fills available space */
  flex: 0 0 auto;    /* Don't grow or shrink (fixed size) */
  flex: 1 1 200px;   /* Grow, shrink, start at 200px */

  /* Override container's align-items for this item */
  align-self: center;
}
Enter fullscreen mode Exit fullscreen mode

Practical Flexbox Patterns

<!-- Pattern 1: Center anything (the #1 use case) -->
<div class="center">
  <div class="content">Perfectly centered</div>
</div>
<style>
.center {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}
</style>

<!-- Pattern 2: Navigation bar -->
<nav class="navbar">
  <a href="/" class="logo">Brand</a>
  <div class="nav-links">
    <a href="/products">Products</a>
    <a href="/about">About</a>
    <a href="/contact">Contact</a>
  </div>
  <button class="cta">Sign Up</button>
</nav>
<style>
.navbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 2rem;
}
.nav-links { display: flex; gap: 2rem; }
.cta { margin-left: auto; } /* Push to right */
</style>

<!-- Pattern 3: Card grid with auto-sizing -->
<div class="card-grid">
  <div class="card">Short content</div>
  <div class="card">Medium length content here</div>
  <div class="card">This card has much more content than the others</div>
</div>
<style>
.card-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}
.card {
  flex: 1 1 300px; /* Grow, shrink, base 300px */
  /* Cards auto-size: min 300px, share remaining equally */
}
</style>

<!-- Pattern 4: Sticky footer -->
<body class="app-layout">
  <header>Header</header>
  <main>Content that pushes footer down</main>
  <footer>Footer always at bottom</footer>
</body>
<style>
.app-layout {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}
main { flex: 1; } /* Takes all available space */
</style>

<!-- Pattern 5: Media object (avatar + text) -->
<div class="media">
  <img src="avatar.jpg" class="media-img" alt="">
  <div class="media-body">
    <h4>Name</h4>
    <p>Description text goes here</p>
  </div>
</div>
<style>
.media { display: flex; align-items: flex-start; gap: 1rem; }
.media-img { flex-shrink: 0; width: 48px; height: 48px; border-radius: 50%; }
.media-body { flex: 1; min-width: 0; } /* min-width:0 enables text truncation */
</style>
Enter fullscreen mode Exit fullscreen mode

CSS Grid Fundamentals

Core Concepts

.container {
  display: grid;

  /* Define columns */
  grid-template-columns: 200px 1fr 200px;        /* 3 fixed/flexible columns */
  grid-template-columns: repeat(3, 1fr);           /* 3 equal columns */
  grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); /* Responsive! */
  grid-template-columns: 200px repeat(2, 1fr) 100px; /* Mixed sizes */

  /* Define rows */
  grid-template-rows: auto 1fr auto;              /* Header, content, footer height */
  grid-template-rows: masonry;                    /* Masonry layout (experimental but useful) */

  /* Shorthand for columns + rows */
  grid-template:
    "header header header" 60px
    "sidebar main   ads"    1fr
    "footer footer footer" 40px
    / 200px 1fr 200px;

  /* Gap */
  gap: 20px;
  row-gap: 10px;
  column-gap: 15px;

  /* Justify (column axis = horizontal) */
  justify-items: start;     /* Default: stretch */
  justify-content: center;  /* When total grid size < container */

  /* Align (row axis = vertical) */
  align-items: center;
  align-content: center;    /* When total grid size < container */

  /* Place items in the grid */
  place-items: center;      /* Shorthand: align-items + justify-items */
}

.item {
  /* Position items explicitly */
  grid-column: 1 / -1;     /* Span from first to last column line */
  grid-column: 1 / span 2; /* Start at col 1, span 2 columns */
  grid-row: 2 / 3;

  /* Shorthand */
  grid-area: 2 / 1 / 3 / 2; /* row-start / col-start / row-end / col-end */

  /* Or use named areas from grid-template */
  grid-area: header;

  /* Override alignment for this item */
  justify-self: center;
  align-self: start;
}
Enter fullscreen mode Exit fullscreen mode

Practical Grid Patterns

<!-- Pattern 1: Holy Grail Layout (header + 3-col + footer) -->
<div class="holy-grail">
  <header>Header</header>
  <nav>Sidebar Nav</nav>
  <main>Main Content Area</main>
  <aside>Ads / Extras</aside>
  <footer>Footer</footer>
</div>
<style>
.holy-grail {
  display: grid;
  grid-template:
    "hd hd hd" auto
    "nav main aside" 1fr
    "ft ft ft" auto
    / 200px 1fr 200px;
  min-height: 100vh;
  gap: 1rem;
}
header { grid-area: hd; }
nav { grid-area: nav; }
main { grid-area: main; }
aside { grid-area: aside; }
footer { grid-area: ft; }

/* Responsive: collapse to single column on mobile */
@media (max-width: 768px) {
  .holy-grail {
    grid-template:
      "hd" auto
      "nav" auto
      "main" 1fr
      "aside" auto
      "ft" auto
      / 1fr;
  }
}
</style>

<!-- Pattern 2: Responsive Card Grid -->
<div class="grid-cards">
  <div class="card">Card 1</div>
  <div class="card">Card 2</div>
  <div class="card">Card 3</div>
  <div class="card">Card 4</div>
  <div class="card">Card 5</div>
  <div class="card">Card 6</div>
</div>
<style>
.grid-cards {
  display: grid;
  /* Auto-fill: creates as many 250px+ columns as will fit */
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.5rem;
}
/* No media query needed! Columns adjust automatically */
/* Wide screen: 4 columns → Medium: 3 → Tablet: 2 → Phone: 1 */
</style>

<!-- Pattern 3: Dashboard Grid -->
<div class="dashboard">
  <div class="widget widget-wide">Chart (spans 2 cols)</div>
  <div class="widget">Stats</div>
  <div class="widget">Activity</div>
  <div class="widget widget-tall">Table (spans 2 rows)</div>
  <div class="widget">Alerts</div>
</div>
<style>
.dashboard {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px;
  gap: 1rem;
}
.widget { background: white; border-radius: 8px; padding: 1rem; }
.widget-wide { grid-column: span 2; }
.widget-tall { grid-row: span 2; }
</style>

<!-- Pattern 4: Feature comparison table -->
<div class="comparison-grid">
  <div class="cell header">Feature</div>
  <div class="cell header">Free</div>
  <div class="cell header">Pro</div>
  <div class="cell">Storage</div>
  <div class="cell">1 GB</div>
  <div class="cell">Unlimited</div>
  <div class="cell">API Access</div>
  <div class="cell"></div>
  <div class="cell"></div>
</div>
<style>
.comparison-grid {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr;
  gap: 1px;
  background: #e0e0e0; /* Creates borders via gaps */
  border: 1px solid #e0e0e0;
}
.cell { background: white; padding: 0.75rem; }
.cell.header { font-weight: bold; background: #f5f5f5; }
</style>
Enter fullscreen mode Exit fullscreen mode

Flexbox vs Grid: Decision Guide

Choose FLEXBOX when:
✓ Laying out items in ONE direction (row OR column)
✓ Distributing space between items (justify-content)
✓ Aligning items vertically within a container
✓ Content-driven sizing (items size based on their content)
✓ Navigation bars, card rows, form inputs, centering

Choose GRID when:
✓ TWO-dimensional layout (rows AND columns needed)
✓ Overlapping elements (explicit placement)
✓ Complex page-level layouts (holy grail, dashboard)
✓ Items need to span multiple rows/columns
✓ Precise control over both axes simultaneously

Common combo: Grid for PAGE layout → Flexbox for COMPONENT layout
Enter fullscreen mode Exit fullscreen mode

Modern Tricks You Might Not Know

/* Subgrid: Child grid inherits parent's track definitions */
.card-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 1rem;
}
.card {
  display: grid;
  grid-template-rows: subgrid; /* Inherits row tracks from parent! */
  gap: inherit;                /* Inherits the same gap */
}

/* Container queries: Style based on container size, not viewport! */
.card-container {
  container-type: inline-name;
  container-name: card;
}
@container card (min-width: 400px) {
  .card-inner { flex-direction: row; } /* Horizontal layout when wide enough */
}
@container card (max-width: 399px) {
  .card-inner { flex-direction: column; } /* Stack vertically when narrow */
}

/* Logical properties (for RTL/internationalization support) */
.element {
  /* Instead of left/right/top/bottom: */
  margin-inline-start: 1rem;   /* = margin-left in LTR, margin-right in RTL */
  margin-block-end: 0.5rem;    /* = margin-bottom */
  inset-inline: 0;             /* = left: 0; right: 0; */

  /* For flex/grid: */
  justify-content: flex-start; /* Works correctly in both directions */
}

/* aspect-ratio: Maintain proportions without padding hack */
.avatar {
  width: 100%;
  aspect-ratio: 1 / 1;         /* Perfect square */
  object-fit: cover;
}
.video-thumbnail {
  aspect-ratio: 16 / 9;
  object-fit: cover;
}

/* gap works with flexbox too! (not just grid) */
.form-row {
  display: flex;
  gap: 1rem;                  /* No more negative margin hacks! */
}

/* :has() selector — the "parent selector" we've been waiting for */
fieldset:has(:invalid) {
  border-color: red;          /* Style parent based on children! */
}
.card:has(.featured-badge) {
  border: 2px solid gold;
}
Enter fullscreen mode Exit fullscreen mode

Debugging Layout Issues

/* Quick debug: visualize your grid/flex structure */
.debug-grid {
  outline: 1px solid red;     /* Shows element boundaries */
}
/* Or use browser DevTools: Inspect → Layout panel */

/* Common issues and fixes: */

/* Issue: Items not centering? */
/* Fix: Make sure container has a defined height/min-height */
.center-container {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 400px; /* ← This is often missing! */
}

/* Issue: Grid items not respecting grid-template? */
/* Fix: Check if implicit grid is being created by extra items */
.grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  /* If you have 5 items, the 5th one creates an IMPLICIT new row */
  grid-auto-columns: 200px;   /* Control implicit column sizes */
  grid-auto-rows: 100px;      /* Control implicit row sizes */
}

/* Issue: Overflow on flex items? */
/* Fix: Allow shrinking or set min-width: 0 */
.flex-item {
  flex: 1;
  min-width: 0;              /* Allows content to shrink below content size */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Issue: Gap not working? */
/* Fix: Gap doesn't work between margin:auto pushed items */
/* Use gap with flexbox, avoid combining with margin: auto on children */
Enter fullscreen mode Exit fullscreen mode

What CSS layout problem took you longest to solve?

Follow @armorbreak for more practical developer guides.

Top comments (0)