DEV Community

Alex Chen
Alex Chen

Posted on

CSS Layout in 2026: Flexbox, Grid, and When to Use Each (2026)

CSS Layout in 2026: Flexbox, Grid, and When to Use Each (2026)

Stop guessing with margins and floats. Here's how modern CSS layout actually works.

The Evolution

1990s: Table layouts (don't ask)
2000s: Float-based layouts (clearfix hacks everywhere)
2010s: Flexbox (one-dimensional layout savior)
2020s: Grid (two-dimensional layout done right)
2026: Flexbox + Grid + Container Queries = complete toolkit
Enter fullscreen mode Exit fullscreen mode

Quick Decision Guide

Need to lay out items in ONE direction?
→ Use FLEXBOX (row or column)

Need to lay out items in TWO directions (rows AND columns)?
→ Use GRID

Need a component that adapts to its container size?
→ Use CONTAINER QUERIES + Grid/Flexbox

Simple centering?
→ Either works (Flexbox is shorter)
Enter fullscreen mode Exit fullscreen mode

Flexbox Deep Dive

The Core Concept

/* Flexbox = one-dimensional layout */
/* Items flow in either a ROW or a COLUMN */

.container {
  display: flex;
  /* Main axis: horizontal by default */
  /* Cross axis: perpendicular to main axis */
}
Enter fullscreen mode Exit fullscreen mode

Direction & Wrapping

.container {
  display: flex;

  /* Main axis direction */
  flex-direction: row;         /* left → right (default) */
  flex-direction: row-reverse;  /* right → left */
  flex-direction: column;       /* top → bottom */
  flex-direction: column-reverse;/* bottom → top */

  /* Wrapping behavior */
  flex-wrap: nowrap;   /* single line, shrink if needed (default) */
  flex-wrap: wrap;     /* multi-line, flows to next line */
  flex-wrap: wrap-reverse; /* wraps in reverse order */
}

/* Shorthand */
flex-flow: row wrap; /* direction + wrap together */
Enter fullscreen mode Exit fullscreen mode

Alignment (This Is Where Most People Get Stuck)

.container {
  display: flex;

  /* MAIN AXIS alignment (justify) */
  justify-content: flex-start;  /* pack to start (default) */
  justify-content: flex-end;    /* pack to end */
  justify-content: center;      /* center horizontally */
  justify-content: space-between; /* equal space BETWEEN items */
  justify-content: space-around;  /* equal space AROUND items */
  justify-content: space-evenly;  /* exactly equal space everywhere */

  /* CROSS AXIS alignment (align) — controls the OTHER dimension */
  align-items: stretch;    /* stretch to fill (default) */
  align-items: flex-start; /* align to cross-axis start */
  align-items: flex-end;   /* align to cross-axis end */
  align-items: center;     /* center vertically */
  align-items: baseline;   /* align text baselines */
}

/* Visual reference:

   justify-content (main axis →):
   ┌─────────────────────────────┐
   │ [item]   [item]   [item]  │  space-between
   │ [item] [item] [item] [item]│  space-evenly
   │        [item] [item]       │  center

   align-items (cross axis ↓):
   ┌──┐
   │  │ item  flex-start
   ├──┤
   │  │ item  center
   ├──┤
   │  │ item  flex-end
   └──┘
*/
Enter fullscreen mode Exit fullscreen mode

Item-Level Control

.item {
  /* How much can this item grow? */
  flex-grow: 0;   /* don't grow (default) */
  flex-grow: 1;   /* grow equally with siblings */
  flex-grow: 2;   /* grow 2x as much as flex-grow:1 siblings */

  /* How much can this item shrink? */
  flex-shrink: 1;  /* shrink equally (default) */
  flex-shrink: 0;  /* never shrink (important for icons/buttons!) */

  /* Base size before growing/shrinking */
  flex-basis: auto; /* use content size (default) */
  flex-basis: 200px; /* start at 200px */
  flex-basis: 0;     /* start at 0 (useful for equal-width items) */

  /* Override container's align-items for this specific item */
  align-self: center; /* this item centers itself */
  align-self: flex-start; /* this item sticks to start */
}

/* Shorthand: grow | shrink | basis */
flex: 1;        /* flex-grow: 1; flex-shrink: 1; flex-basis: 0% */
flex: 0 0 auto; /* don't grow, don't shrink, use content size */
flex: 1 1 200px; /* grow, shrink, start at 200px */

/* THE magic trick: equal-width children */
.equal-children > * {
  flex: 1;
}
Enter fullscreen mode Exit fullscreen mode

Real-World Flexbox Patterns

/* Pattern 1: Perfect centering (the #1 use case) */
.center-all {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 100vh;
}

/* Pattern 2: Navbar */
.navbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem 2rem;
}
.navbar > .logo { flex-shrink: 0; }
.navbar > .nav-links { display: flex; gap: 1rem; }

/* Pattern 3: Card with sticky footer */
.card {
  display: flex;
  flex-direction: column;
}
.card-body { flex: 1; }  /* Takes all available space */
.card-footer { /* normal size, stays at bottom */ }

/* Pattern 4: Media object (avatar + text) */
.media-object {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
}
.media-object > .avatar {
  flex-shrink: 0; /* Avatar never squishes */
  width: 48px;
  height: 48px;
}
.media-object > .content { flex: 1; } /* Text takes rest */

/* Pattern 5: Form row */
.form-row {
  display: flex;
  gap: 1rem;
  flex-wrap: wrap; /* Responsive: wraps on small screens */
}
.form-row > * {
  flex: 1 1 200px; /* Min 200px, grow equally */
}

/* Pattern 6: Loading spinner overlay */
.loading-overlay {
  position: fixed;
  inset: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  background: rgba(0, 0, 0, 0.5);
}
Enter fullscreen mode Exit fullscreen mode

CSS Grid Deep Dive

The Core Concept

/* Grid = two-dimensional layout */
/* Define rows AND columns explicitly */

.container {
  display: grid;
  /* Define columns */
  grid-template-columns: 200px 1fr 200px;
  /* Define rows */
  grid-template-rows: auto 1fr auto;
  /* Gap between cells */
  gap: 1rem;
}
Enter fullscreen mode Exit fullscreen mode

The fr Unit (Game Changer)

/* fr = "fraction of available space" */

.grid-3-equal {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr; /* Three equal columns */
}

.grid-sidebar {
  display: grid;
  grid-template-columns: 250px 1fr; /* Fixed sidebar + fluid content */
}

.grid-complex {
  display: grid;
  grid-template-columns: 200px 1fr 300px; /* Left nav + content + right panel */
  grid-template-rows: 60px 1fr 40px; /* Header + main + footer */
}

/* repeat() saves typing */
.grid-12 {
  display: grid;
  grid-template-columns: repeat(12, 1fr); /* 12-column grid system */
}

/* minmax() for responsive without media queries */
.responsive-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
  /* Automatically creates as many 250px+ columns as fit */
  gap: 1rem;
}
Enter fullscreen mode Exit fullscreen mode

Placing Items

.container {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: auto auto auto;
  gap: 1rem;
}

/* Method 1: Auto-placement (items flow in order) */
.item { /* just place them, they'll fill cells */ }

/* Method 2: Line-based placement */
.header {
  grid-column: 1 / -1; /* From column 1 to last column */
  grid-row: 1 / 2;
}

.sidebar {
  grid-column: 1 / 2;
  grid-row: 2 / 4; /* Spans rows 2 and 3 */
}

.main {
  grid-column: 2 / -1;
  grid-row: 2 / 3;
}

/* Method 3: Named areas (most readable!) */
.dashboard {
  display: grid;
  grid-template-areas:
    "header header header"
    "sidebar main main"
    "sidebar footer footer";
  grid-template-columns: 200px 1fr 1fr;
  grid-template-rows: auto 1fr auto;
  gap: 1rem;
}

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

/* Method 4: span keyword */
.featured {
  grid-column: span 2; /* Spans 2 columns */
  grid-row: span 2;    /* Spans 2 rows */
}
Enter fullscreen mode Exit fullscreen mode

Alignment in Grid

.container {
  display: grid;

  /* Align content within grid area */
  justify-items: start;   /* horizontal alignment inside cell */
  align-items: start;     /* vertical alignment inside cell */
  /* Values: start, end, center, stretch */

  /* Align entire grid tracks when smaller than container */
  justify-content: center; /* center the whole grid */
  align-content: center;

  /* Per-item override */
  .specific-item {
    justify-self: end;
    align-self: center;
  }
}
Enter fullscreen mode Exit fullscreen mode

Real-World Grid Patterns

/* Pattern 1: Holy Grail Layout */
.holy-grail {
  display: grid;
  grid-template:
    "header header header" auto
    "nav    content aside" 1fr
    "footer footer footer" auto
    / 200px 1fr 200px;
  min-height: 100vh;
  gap: 1rem;
}

/* Pattern 2: Card Grid (responsive) */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 1.5rem;
}
/* No media queries needed! Cards reflow automatically */

/* Pattern 3: Dashboard */
.dashboard-grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  grid-template-rows: auto 1fr auto;
  gap: 1rem;
}
.widget-wide  { grid-column: span 2; }
.widget-tall   { grid-row: span 2; }

/* Pattern 4: Image gallery (Masonry-like) */
.gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-auto-rows: 200px;
  gap: 0.5rem;
}
.gallery img:nth-child(5n+1) { grid-row: span 2; } /* Some images taller */

/* Pattern 5: Form layout */
.form-grid {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 1rem;
  align-items: center;
}
.form-grid label { text-align: right; }
.form-grid .full-width { grid-column: span 2; }

/* Pattern 6: Feature comparison table */
.comparison-table {
  display: grid;
  grid-template-columns: 2fr repeat(3, 1fr);
  gap: 1px;
  background: #e0e0e0; /* Gap color = border effect */
}
.comparison-table > * {
  background: white;
  padding: 1rem;
}
Enter fullscreen mode Exit fullscreen mode

Container Queries (2026 Essential)

/* Media queries: style based on VIEWPORT size */
/* Container queries: style based on CONTAINER size */

/* Define a container */
.card-container {
  container-type: inline-size;
  container-name: card;
}

/* Style based on container width, not viewport! */
@container card (min-width: 400px) {
  .card-inner {
    display: grid;
    grid-template-columns: 200px 1fr;
  }
}

@container card (min-width: 600px) {
  .card-inner {
    grid-template-columns: 250px 1fr 150px;
  }
}

/* This means your component looks great ANYWHERE:
   In a sidebar, in a modal, in a grid cell, in full page.
   The component adapts to its own space! */
Enter fullscreen mode Exit fullscreen mode

When to Use What

Layout Need Best Tool
Center one element Flexbox (shorter)
Navigation bar Flexbox
Card components Flexbox (column)
Overall page layout Grid
Dashboard with panels Grid
Photo gallery Grid
Form alignment Grid (or Flexbox)
Sticky footer Flexbox
Equal-height columns Flexbox (align-items: stretch)
Complex overlapping Grid (grid-area)
Component that adapts anywhere Container Query + Grid/Flex

Common Mistakes

/* ❌ Using margin: 0 auto for everything */
.center-old-school {
  width: 80%;
  margin: 0 auto; /* Only works with explicit width */
}

/* ✅ Modern centering */
.center-modern {
  display: flex;
  justify-content: center;
  align-items: center;
}

/* ❌ Float-based layout */
.float-layout::after {
  content: "";
  clear: both;
  display: table;
}
.left { float: left; }
.right { float: right; }

/* ✅ Don't use floats for layout in 2026 */
.flex-layout { display: flex; }
.grid-layout { display: grid; }

/* ❌ Fixed heights */
.sidebar { height: 500px; } /* Breaks on any content change */

/* ✅ Let content determine height */
.sidebar { 
  /* Just let it flow naturally */
  overflow-y: auto; /* Scroll only if needed */
}

/* ❌ Negative margins for positioning */
.bad-positioning { margin-top: -50px; }

/* ✅ Use proper layout tools */
.good-positioning { 
  display: grid;
  grid-row: 1 / 3; /* Overlap properly */
}
Enter fullscreen mode Exit fullscreen mode

Are you team Flexbox, team Grid, or "it depends"?

Follow @armorbreak for more practical web dev guides.

Top comments (0)