Web DevelopmentLayout reference2026 edition

CSS Grid and Flexbox: Complete Layout Reference 2026

Complete 2026 CSS Grid and Flexbox reference — properties, patterns, subgrid, container queries, responsive layouts, and when to pick each one.

Digital Applied Team
April 11, 2026
12 min read
100%

Subgrid browser support

95%+

Container query support

~1 in 3

Top sites use CSS Grid

30-60KB

CSS saved per project

Key Takeaways

Flex for one axis, Grid for two:: Use Flexbox to distribute items along a single row or column; use Grid when rows and columns must align to each other.
Subgrid is production-ready in 2026:: All evergreen browsers support subgrid. Stop hacking card-row alignment with fixed heights — let children inherit the parent grids tracks.
Container queries replace most breakpoints:: @container lets components respond to their own width, not the viewport. Build once, drop into any slot at any width.
Reading order is not visual order:: order, flex-direction: row-reverse, and grid-area reorder visuals, not the accessibility tree. Screen readers and keyboards follow DOM order.
gap is the best spacing API:: Use gap on flex and grid parents instead of margins on children. It composes cleanly with wrapping and removes last-child margin hacks.
Hybrid wins real layouts:: Grid for the page skeleton, Flex for component internals (nav bars, buttons, form rows). Neither tool is a complete answer alone.
Tailwind v4 ships both layers:: Modern utilities cover every property here — grid-cols, auto-fit helpers, place-content, container-type. Use shrink and grow, not flex-shrink and flex-grow.

Flexbox container properties

Flexbox distributes space along a single axis. Setting display: flex on a parent turns it into a flex container and every direct child becomes a flex item. Eight properties on the container cover nearly every real-world use case. Most modern layout bugs stem from confusing the main axis and the cross axis, so anchor your mental model there first.

display: flex and inline-flex
Activate the flex layout mode

display: flex creates a block-level flex container — the element itself participates in block layout but its children are laid out with flex rules. display: inline-flex is identical internally but the container flows inline with surrounding text, useful for pill-shaped buttons that must sit next to other inline content.

flex-direction
Defines the main axis orientation

Accepts row (default), row-reverse, column, and column-reverse. Choosing the direction flips the meaning of justify-content (main axis) and align-items (cross axis). Reverse values only change visual order — keyboard and screen reader order still follow the DOM, so never use flex-direction: row-reverse to move the first-tabbable element to the right.

flex-wrap and flex-flow
Allow items to wrap to new lines

Default nowrap forces children onto one line, shrinking if necessary. wrap lets overflow spill to a new line in the same direction; wrap-reverse fills upward. flex-flow is a shorthand combining flex-direction and flex-wrap — rarely used in production because splitting the two values reads better at review time.

gap, row-gap, column-gap
The canonical spacing API in 2026

gap replaces every margin-right hack you have ever written. Applied to the flex parent, it inserts equal spacing between children without affecting outer edges. Works correctly with flex-wrap, keeps spacing consistent across rows when items wrap, and removes the need for last-child selectors. Universal browser support since 2021.

justify-content
Distributes items along the main axis

Values: flex-start, flex-end, center, space-between, space-around, space-evenly. space-between pins first and last items to the edges and distributes the rest equally — the canonical pattern for top navigation bars with logo on one side and nav links on the other.

align-items and align-content
Cross-axis alignment, single line versus multi-line

align-items controls cross-axis alignment of items within each line. align-content controls spacing between lines when content wraps onto multiple lines. If flex-wrap is nowrap, align-content has no effect. Values mirror justify-content with the addition of baseline for aligning text baselines across items of varying font sizes.

place-content shorthand
Sets align-content and justify-content together

place-content: center is the one-liner for centering wrapped content both axes. place-items: center does the same for items-level alignment. These shorthands work identically in Flex and Grid containers, which makes rote centering trivial.

/* Navigation bar with logo left, links right */
.nav {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1.5rem;
  padding: 1rem 2rem;
}

/* Card row that wraps on narrow screens */
.cards {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
}

/* Perfect center, single child */
.hero {
  display: flex;
  min-height: 60vh;
  place-content: center;
}

Flexbox item properties

Properties applied to flex children control how they grow, shrink, and place themselves inside the parent. The three sizing properties — grow, shrink, basis — are the most commonly misunderstood. Pair them with flex shorthand, align-self for per-child overrides, and order for visual rearrangement when it is safe to do so.

flex-grow
How much free space an item claims

A unitless proportion. flex-grow: 0 (default) means the item stays at its content size; flex-grow: 1 means it grows to absorb available space. If multiple items have grow values, space is distributed in proportion — an item with flex-grow: 2 gets twice the expansion of a sibling with flex-grow: 1. Tailwind v4 exposes this as the grow utility (not flex-grow).

flex-shrink
How aggressively an item shrinks under pressure

Default flex-shrink: 1 means items shrink proportionally when the container is too narrow. flex-shrink: 0 prevents shrinking entirely — crucial for fixed-size icons or logos that must never squeeze. Tailwind v4 exposes this as shrink and shrink-0. Legacy flex-shrink classes are deprecated — use shrink.

flex-basis
The starting size before grow/shrink distribute space

Analogous to width on the main axis but participates in flex calculations. flex-basis: auto uses the content size; flex-basis: 0 collapses the starting size so grow values divide space purely by ratio. flex-basis: 200px starts every item at 200 pixels before grow and shrink adjust.

flex shorthand
grow, shrink, and basis combined

Three common presets: flex: 0 1 auto (default), flex: 1 1 0 (equal columns that share space), flex: 0 0 auto (content size, never grows or shrinks). flex: 1 is shorthand for 1 1 0 — the most useful one-liner for fluid equal columns.

align-self
Per-child override of align-items

When most children align one way but a single item needs different cross-axis placement — for example, a dropdown arrow that must stay top-right while text wraps below — apply align-self to that child. Accepts the same values as align-items plus auto to inherit.

order
Visual reordering — use with caution

Default order: 0. Lower values render first, higher values render last. Useful for locale-specific layouts or swapping card positions at certain breakpoints. Warning: order only changes visual order, not DOM order. Keyboard tab sequence and screen reader flow still follow source order, so never use order for content that must be read first.

/* Three equal columns that share available width */
.column {
  flex: 1 1 0;
}

/* Fixed sidebar, flexible main content */
.sidebar { flex: 0 0 280px; }
.main    { flex: 1 1 0; }

/* Icon next to text, icon never shrinks */
.button-icon { flex-shrink: 0; }
/* Or in Tailwind v4: class="shrink-0" */

Grid container properties

CSS Grid is a two-dimensional system: rows and columns cooperate in a single layout calculation. The container defines the track sizes; children opt into specific tracks or let auto-placement fill them. Grid is the right tool for page scaffolds, dashboards, card decks, and any layout where alignment across both axes matters.

display: grid and inline-grid
Activate the grid layout mode

display: grid creates a block-level grid container; display: inline-grid keeps the container in the inline flow. Children become grid items regardless of their own display value (with minor edge cases around tables).

grid-template-columns and grid-template-rows
Declare the track sizes

Accepts any CSS length (px, rem, %), the fr unit for fractional space, auto for content-sized tracks, and the functions minmax(), repeat(), fit-content(), and min-content / max-content. repeat(auto-fit, minmax(240px, 1fr)) is the single most useful pattern in the language — it creates as many equal-width columns as fit, each at least 240 pixels wide.

grid-template-areas
Named regions for readable page scaffolds

Declares named areas as ASCII art, then children reference those names with grid-area. The result reads almost like the layout itself — especially valuable for team review and breakpoint changes. Empty cells use a period; shared names across adjacent cells spans that region.

grid-auto-columns and grid-auto-rows
Size implicit tracks

When items overflow the explicit track definition, the grid creates implicit tracks on demand. grid-auto-rows controls their default height. Combined with grid-auto-flow: dense, it enables packing layouts similar to Pinterest-style masonry without JavaScript.

gap (row-gap, column-gap)
Track spacing without margins

Same API as Flexbox. gap: 1.5rem inserts uniform spacing between rows and columns with no outer margins. Shorthand accepts two values — gap: 1rem 2rem sets row-gap and column-gap separately.

place-items and place-content
Align both axes with one property

place-items sets align-items and justify-items in one go (inside each cell). place-content sets align-content and justify-content (the whole track area inside the container when tracks are smaller than the container). Use place-items: center for quick one-off centering of every cell.

/* Responsive card grid — as many columns as fit */
.cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: 1.5rem;
}

/* Named-area page scaffold */
.page {
  display: grid;
  grid-template-columns: 240px 1fr;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header header"
    "aside  main"
    "footer footer";
  min-height: 100dvh;
}
.page > header { grid-area: header; }
.page > aside  { grid-area: aside; }
.page > main   { grid-area: main; }
.page > footer { grid-area: footer; }

Grid item properties

Grid items use a handful of properties to place themselves into specific tracks, span multiple cells, and override alignment. These properties work in two syntactic styles: numeric line references (grid-column: 2 / 5) and named areas (grid-area: main). Mix as convenient — the browser flattens both to the same internal representation.

grid-column and grid-row
Place an item on specific tracks

Shorthand for grid-column-start / grid-column-end (and the row equivalents). grid-column: 1 / 3 means from line 1 to line 3 — spanning two columns. Lines are numbered from 1 starting at the left/top; negative numbers count from the right/bottom (-1 is the last line).

span notation
Declare length without computing end lines

grid-column: span 2 says "occupy two columns starting from auto-placement." More robust than hard-coded line numbers when the parent grid changes. Combine with named lines (span main-start / main-end) for expressive layouts.

grid-area
Named placement or four-value shorthand

Two uses: point to a named area (grid-area: main) or set row-start / column-start / row-end / column-end in one line (grid-area: 2 / 1 / 4 / 3). Named areas are far more readable and survive refactors without hunting through line numbers.

justify-self and align-self
Per-item placement inside the cell

Grid items fill their cell by default. justify-self and align-self constrain the item to start, end, center, or stretch within the allocated area. place-self shorthand sets both. Useful for a single element that must stay pinned to a corner while siblings stretch.

/* Hero that spans the full width of a 12-column grid */
.hero { grid-column: 1 / -1; }

/* Feature card that spans 2 columns, 2 rows */
.feature {
  grid-column: span 2;
  grid-row: span 2;
}

/* Pull-quote pinned to the right in a content cell */
.pullquote {
  justify-self: end;
  align-self: start;
  max-width: 18rem;
}

Subgrid (2026 support)

Subgrid lets a nested grid inherit its parents track definitions instead of creating new ones. The effect solves a problem that plagued CSS for years: making content inside sibling cards align to a shared baseline even though each card has its own internal structure. By 2026 subgrid is universally supported across Chrome, Edge, Safari, Firefox, and every mobile browser that matters.

How subgrid works
Inherit parent tracks instead of defining local ones

Declare grid-template-columns: subgrid or grid-template-rows: subgrid on a child grid. The child now participates in the parents grid tracks — all its grid children snap to the same column or row lines as the outer grid. You can subgrid one axis and define the other locally, which is the most common production pattern.

Aligning card rows across a parent grid
The canonical subgrid use case

A typical card has an image, title, description, and CTA. Across a deck of cards, titles of different lengths push CTAs down at inconsistent heights. Subgrid fixes this: the parent grid defines rows for image, title, description, CTA. Each card subgrids the row axis and places its children onto those rows — every CTA snaps to the same row line.

Browser support (2026)
Effectively universal

Firefox shipped subgrid first (2019), Safari followed (2022), and Chromium landed it in Chrome 117 (September 2023). Edge matches Chromium. By 2026 the feature is stable, fast, and reliable. No feature detection needed for mainstream audiences — use it directly.

Container queries (2026 production-ready)

Container queries let components style themselves based on the size of an ancestor, not the viewport. This closes a long-standing gap in CSS: a reusable card that adapts to whatever column it happens to sit in. Combined with the :has() selector and Grid, container queries make truly context-aware components possible without JavaScript measurement.

container-type
Marks an element as a query container

container-type: inline-size is the common choice — it lets descendants query the containers inline size (width in left-to-right languages) without forcing the container into size containment on both axes. container-type: size is available but imposes stronger containment and is rarely needed.

container-name
Optional name for targeting specific ancestors

When components nest inside other query containers, name them so @container rules can target the right ancestor. container: card / inline-size is shorthand for setting both name and type. Then @container card (min-width: 480px) applies only to that named container.

@container rules
Scoped breakpoints for the ancestor, not the viewport

Syntax mirrors @media: @container (min-width: 500px) fires when the nearest ancestor query container reaches 500 pixels. This means the same component renders compact in a 320-pixel sidebar and expanded in a 900-pixel main column — with one stylesheet.

Relationship with Grid and Flex
Layout parent, not query parent

Mark a wrapper as container-type, then its Grid or Flex children can react to that wrappers width. Common pattern: Grid lays out a list of cards; each card is its own container so it changes layout based on the slot width assigned by the Grid parent. This is how you build components that look correct in any layout slot.

Tailwind v4 container queries
First-class variant support

Tailwind v4 ships container query variants out of the box. Apply @container on a wrapper, then use @sm:grid-cols-2, @md:flex-row, and so on for descendant styling. No plugin, no configuration. This removes almost every reason to reach for viewport-sized breakpoints on component internals.

Common layout patterns

Five patterns cover roughly 90% of real production pages. Each has a minimal canonical form — learn those first, then adapt. Review the website launch checklist for QA patterns that catch layout regressions before deploy.

The Holy Grail layout

Header, footer, fixed-width sidebars on each side, flexible main content. For decades developers built this with floats and negative margins. Grid collapses it to six lines.

.holy-grail {
  display: grid;
  grid-template-columns: 220px 1fr 220px;
  grid-template-rows: auto 1fr auto;
  grid-template-areas:
    "header  header  header"
    "left    main    right"
    "footer  footer  footer";
  min-height: 100dvh;
}

Responsive card grid with minmax and auto-fit

The most useful grid pattern in CSS. minmax sets a floor and ceiling for each column; auto-fit creates as many columns as fit. The grid reflows at every viewport size with no media queries.

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

Sidebar with collapsing aside

Fixed sidebar next to fluid main. On narrow containers the sidebar collapses below. Use container queries so the component works regardless of where it sits.

.with-sidebar {
  container-type: inline-size;
  display: grid;
  grid-template-columns: 240px 1fr;
  gap: 1.5rem;
}
@container (max-width: 640px) {
  .with-sidebar { grid-template-columns: 1fr; }
}

Magazine and editorial layouts

Irregular grids with large hero cells, image spans, and pull-quotes benefit from named grid areas and explicit span. Designers ship layouts that used to require a CMS plus custom templating; Grid expresses them in CSS alone.

.magazine {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: 1.5rem;
}
.magazine .hero     { grid-column: 1 / -1; }
.magazine .feature  { grid-column: span 4; }
.magazine .sidecar  { grid-column: span 2; }

12-column fluid grid

The 12-column grid remains the most compatible system for design handoff because Figma, Sketch, and every design tool defaults to it. Build once and children opt into spans.

.grid-12 {
  display: grid;
  grid-template-columns: repeat(12, 1fr);
  gap: 1.5rem;
}
/* Children declare span 1 through 12 */
.col-6 { grid-column: span 6; }
.col-4 { grid-column: span 4; }
.col-3 { grid-column: span 3; }

Grid vs Flexbox decision matrix

The debate is not Grid versus Flexbox — it is when to use each. Both tools are first-class and complement one another. The framework below is the one we apply during architecture review on every rendering-focused build where layout performance matters.

Reach for Flexbox when
  • Items live on a single axis (nav, toolbar, form row)
  • Content size drives layout decisions
  • You need wrap behavior with equal gap
  • Item count is dynamic and unknown at build time
  • Vertical centering a single child in its parent
Reach for Grid when
  • Rows and columns must align to each other
  • Layout is defined structurally in two dimensions
  • You want named regions for team clarity
  • Card decks need consistent row heights (subgrid)
  • Holy Grail, magazine, dashboard, admin scaffold
Hybrid patterns (the realistic answer)
Grid for skeleton, Flex for components

Production pages almost always combine both. Grid handles the page skeleton — header, aside, main, footer. Inside each region, Flexbox lays out the local component (nav links, form rows, button clusters, inline metadata). The two layout modes compose cleanly and each does what it is best at.

Accessibility — reading versus visual order
The biggest modern-layout trap

order, flex-direction: row-reverse, grid-column, and grid-area can rearrange visuals without touching the DOM. The accessibility tree follows DOM order. That means a keyboard user tabs through elements in the order they appear in the markup, a screen reader reads them in source order, and an automated test sees them in source order. If your visual design reorders critical interactive elements, reorder the DOM instead or redesign. This is the most common layout-related WCAG 2.2 failure we catch on audit.

Emerging: CSS anchor positioning
The next piece after subgrid and container queries

CSS anchor positioning (position-try, anchor()) is landing across browsers in 2026. It lets tooltips, popovers, and dropdowns position themselves relative to an arbitrary anchor element — no JavaScript math required. Combined with Grid for layout and container queries for adaptivity, the case for layout libraries shrinks further every year.

Ship Production Layouts Faster

Our engineering team builds accessible, performant layouts on Grid, Flexbox, subgrid, and container queries. We ship production CSS without the legacy scaffolding.

Free consultation
Expert guidance
Tailored solutions

Frequently Asked Questions

Related Articles

Continue exploring with these related guides