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.
Subgrid browser support
Container query support
Top sites use CSS Grid
CSS saved per project
Key Takeaways
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 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.
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.
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 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.
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 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: 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;
}Main axis intuition:Say the flex-direction out loud before reaching for justify or align. Once you verbalize "this is a row, so justify runs horizontally, align runs vertically," alignment bugs disappear. See our web development glossary for related terminology.
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.
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).
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.
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.
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.
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.
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" */Tailwind v4 reminder: Use shrink / shrink-0 and grow / grow-0. The legacy flex-shrink and flex-grow utilities were removed — upgrades will silently drop those classes if you forget to rename them.
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 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).
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.
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.
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.
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 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.
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).
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.
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.
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.
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.
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.
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.
Subgrid replaces the fixed-height hack: Teams that used to force card titles onto one line with line-clamp: 1 or pad to a fixed height with min-height: 4rem can delete that CSS. Subgrid solves the alignment problem without clipping content or locking to arbitrary pixel values.
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: 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.
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.
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.
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 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.
Synergy with :has(): The :has() selector lets a parent style itself based on descendant state — for example, a card with an image renders taller. Combined with container queries, components can self-configure layout without JavaScript at all. See our page speed research for the performance implications.
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.
- 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
- 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
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.
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.
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.
One framework, one call: When in doubt, sketch the layout on paper. If you draw a single line with items on it, use Flex. If you draw a grid of rows and columns, use Grid. If you are nesting Flex containers three deep to fake two dimensions, stop and reach for Grid instead.
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.
Frequently Asked Questions
Related Articles
Continue exploring with these related guides