CSS Grid vs Flexbox

What You Learn From This Page

  • Why Flexbox is primarily one-dimensional and Grid is two-dimensional.
  • How item-based flex sizing differs from track-based grid sizing.
  • Why wrapped flex lines do not create shared columns.
  • When navigation, actions, tags, cards, forms, and page shells favor one model.
  • How alignment, gaps, intrinsic sizes, and responsive wrapping differ.
  • How to combine Grid and Flexbox at different layers of one interface.
  • How visual reordering can affect reading and keyboard order.
  • How to debug layout behavior and choose the simpler correct model.

Introduction

CSS Grid and Flexbox are the two primary layout systems used in modern CSS. They overlap in several capabilities: both can arrange items horizontally or vertically, create gaps, align content, respond to available space, and produce layouts without floats or table markup. That overlap sometimes creates the impression that developers must select one technology for an entire project.

The better approach is to identify the relationship a component needs to express. Flexbox is primarily designed for a one-dimensional relationship along a row or a column. Grid is designed for a two-dimensional relationship in which rows and columns form a shared structure. Flexbox starts with items and distributes space among them. Grid starts with tracks and places items into those tracks.

This distinction is a decision tool, not an absolute prohibition. Grid can create a single row, and Flexbox can wrap into several lines. The important question is whether those additional lines must align with one another. A row of content-sized controls is naturally a Flexbox problem. A collection whose columns must remain aligned across many rows is naturally a Grid problem. Most production interfaces use both.

What Is Flexbox?

Flexbox, formally the Flexible Box Layout model, arranges direct children of a flex container along a main axis. That axis is horizontal for the usual flex-direction: row and vertical for flex-direction: column. The perpendicular direction is the cross axis. Properties on the container and items control alignment, distribution, growth, shrinkage, wrapping, and order.

.toolbar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

A toolbar is a strong Flexbox example because its controls form one sequence. Their widths may differ according to labels, icons, and input values, but they still belong to a single horizontal relationship. If room becomes limited, the design can allow wrapping, scrolling, shrinking, or an alternate responsive state.

What Is CSS Grid?

CSS Grid creates rows and columns and places direct children into the resulting grid areas. The container defines explicit tracks with properties such as grid-template-columns and grid-template-rows. Items can auto-place in source order, occupy named areas, start at selected lines, or span several tracks.

.cards {
  display: grid;
  grid-template-columns:
    repeat(3, minmax(0, 1fr));
  gap: 1rem;
}

Here every row uses the same three column tracks. A card in the second row aligns with the cards above it because the columns belong to the container, not to each individual row. That shared two-dimensional structure is Grid's defining strength.

One Dimension Versus Two Dimensions

The familiar summary says that Flexbox is one-dimensional while Grid is two-dimensional. One-dimensional does not mean horizontal only. A vertical menu, timeline, form stack, or card body can use a column flex container. It means the layout primarily resolves relationships along one main direction at a time.

Grid considers rows and columns as part of one track system. A dashboard can reserve a navigation column, define header and content rows, and let a main region span or align across that structure. When both axes carry meaningful layout relationships, Grid usually communicates the design more directly.

Item-Based Sizing in Flexbox

Flexbox sizing begins with flex items and their bases. Each item has a flex base size derived from flex-basis, width, height, or content. Positive free space may be distributed using flex-grow; negative free space may be removed using flex-shrink. The result depends on the items participating in that flex line.

.sidebar {
  flex: 0 0 18rem;
}

.main {
  flex: 1 1 auto;
  min-width: 0;
}

This model is valuable when individual content boxes should influence their own dimensions. Navigation labels, buttons, tags, and media objects often have different natural widths. Flexbox can preserve those differences while distributing any extra room.

Track-Based Sizing in Grid

Grid sizing focuses on tracks. The container can reserve an 18rem sidebar track and assign the remaining width to a flexible main track. Items occupying the same column share that track's used size, creating alignment across rows.

.layout {
  display: grid;
  grid-template-columns:
    18rem
    minmax(0, 1fr);
}

This centralizes structural decisions on the container. The sidebar and main elements do not each negotiate a separate share through grow factors; they occupy a declared track system. The distinction becomes especially valuable as more regions, rows, spans, or responsive arrangements are added.

Content-Driven and Layout-Driven Thinking

Flexbox is often described as content-driven because item dimensions and flex bases strongly influence the final arrangement. A navigation link called Home and one called Enterprise Solutions can retain their natural widths while a flexible spacer pushes account controls to the far edge.

Grid is often layout-driven because the author commonly establishes the structure first. A page can declare navigation, main, and supplementary columns before their contents are known. These descriptions are useful tendencies rather than strict rules: Grid has intrinsic track sizes, and Flexbox can enforce fixed bases. Choose according to the relationship that should remain stable.

Main Axis and Cross Axis in Flexbox

The main axis follows flex-direction. In a row it normally follows the inline direction; in a column it follows the block direction. justify-content distributes free space along the main axis, while align-items aligns items on the cross axis. Logical directions mean writing mode and text direction affect the visual result.

.actions {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: 0.75rem;
}

This axis model makes Flexbox easy to reason about for a row of actions or a vertical stack. There is one primary progression, and cross-axis alignment controls how items sit within the line.

Rows and Columns Together in Grid

Grid exposes both dimensions directly. A container can define two columns and two rows, and an item may span or align within either dimension. Row sizing and column sizing remain independent but participate in one placement system.

.dashboard {
  display: grid;
  grid-template-columns:
    16rem minmax(0, 1fr);
  grid-template-rows:
    auto minmax(0, 1fr);
}

The header can span both columns, the sidebar can occupy the first column of the second row, and main content can occupy the other area. Expressing this structure with nested one-dimensional flex containers is possible, but Grid usually keeps the relationship clearer.

Alignment Capabilities

Both systems use Box Alignment properties, including justify-content, align-items, and gap. Flexbox aligns items relative to a flex line and its axes. Grid can align the entire track collection inside the container and align items inside individual grid areas.

.center-with-flex {
  display: flex;
  justify-content: center;
  align-items: center;
}

.center-with-grid {
  display: grid;
  place-items: center;
}

Either approach can center a single item. The shorter syntax is not enough to decide the layout model; consider what happens when more content is added. A horizontal group often favors Flexbox, while a cell-based composition may favor Grid.

Flexible Sizing Compared

Flexbox uses flex-grow, flex-shrink, and flex-basis to resolve item sizes. Grid uses track sizing values and functions such as fr, minmax(), auto, min-content, and max-content. Similar-looking ratios are not guaranteed to produce identical results because the algorithms start from different inputs.

.flex-item {
  flex: 1 1 15rem;
}

.grid-container {
  grid-template-columns:
    repeat(3, minmax(15rem, 1fr));
}

The flex declaration gives each item a basis and permission to grow or shrink. The grid declaration creates three shared tracks. Selecting the correct abstraction matters more than making the syntax look equivalent.

Flexbox Wrapping Creates Independent Lines

With flex-wrap: wrap, items move onto new flex lines when they no longer fit. Each line resolves its own free space. Five flexible cards may create three items on the first line and two wider items on the second because the second line distributes its free space among only two participants.

.flex-cards {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.flex-cards > article {
  flex: 1 1 16rem;
}

This behavior is useful when lines are allowed to adapt independently. It is not a defect, and it does not make wrapped Flexbox a two-dimensional track system. It simply reflects the one-dimensional sizing model applied to each line.

Grid Preserves Shared Columns

Grid rows use the same column tracks. A partial final row does not recalculate its own column widths; its items remain aligned to the established columns. This is why Grid is usually preferable for product cards, galleries, dashboards, and repeated records where vertical alignment matters.

.grid-cards {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(16rem, 1fr));
  gap: 1rem;
}

With auto-fit, empty tracks may collapse and occupied tracks may expand. Within each resolved track count, however, rows continue to share the same columns. This gives the collection a stable visual rhythm.

Flexbox for Navigation

A navigation bar is commonly one sequence of content-sized elements: a brand, several links, and account actions. Flexbox aligns these elements without requiring a column definition for every label.

.navbar {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.navbar__account {
  margin-inline-start: auto;
}

The auto inline margin consumes available space and pushes the account area away from the preceding links. This push-away pattern is direct in Flexbox. On narrow screens, the navigation may need a menu, scrolling, wrapping, or a different composition; Flexbox does not determine that product decision automatically.

Flexbox for Toolbars and Action Groups

Toolbars and action groups also express one-dimensional relationships. Controls have content-driven widths, should share a baseline or center line, and usually need consistent gaps. A wrapping flex container can accommodate localization or zoom when the design permits multiple lines.

.dialog-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: 0.75rem;
}

Using Grid with a separate max-content track for each button would add structure without a structural requirement. Flexbox states the intent more clearly: arrange these controls as a group and distribute them along one axis.

Flexbox for Tags and Content-Sized Items

Tags, chips, breadcrumbs, and filters often have unpredictable widths based on content. Their lines do not usually need column alignment. A wrapping flex layout allows each item to keep its natural width and moves items to the next line as needed.

.tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
}

Grid can create a similar visual result with auto-flow and intrinsic tracks, but Flexbox is generally simpler for a sequence of independently sized tokens. The choice follows the content relationship, not the number of lines visible at one width.

Flexbox for a Media Object

A media object places an avatar, thumbnail, or icon beside flexible textual content. It is a row relationship in which one item keeps a stable size and the other consumes the remaining width.

.media {
  display: flex;
  align-items: flex-start;
  gap: 1rem;
}

.media__body {
  flex: 1;
  min-width: 0;
}

The min-width: 0 rule allows long body content to shrink and wrap inside the available space. This intrinsic-size concern appears in both Flexbox and Grid and is an important part of production layout work.

Grid for Card Collections

A card collection typically needs repeated columns, consistent gaps, and alignment across rows. Grid can define that track system once and auto-place any number of direct children.

.cards {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(100%, 16rem), 1fr)
  );
  gap: 1rem;
}

The minimum protects card usability, min(100%, 16rem) avoids overflow in very narrow containers, and the flexible maximum fills each row. This is a structural repeated-track problem, making Grid a better fit than independent flex lines.

Grid for Galleries

Galleries often depend on shared columns and controlled row behavior. Grid can create equal tracks, allow selected items to span, and use auto-placement for the remaining images.

.gallery {
  display: grid;
  grid-template-columns:
    repeat(auto-fill, minmax(12rem, 1fr));
  grid-auto-rows: 10rem;
  gap: 0.75rem;
}

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

Flexbox can wrap images, but spanning two shared columns and two shared rows is not its model. Grid expresses that two-dimensional exception directly.

Grid for Complex Forms

A form with labels aligned in one column and controls aligned in another benefits from shared tracks across rows. Grid can set a content-aware label track and a flexible input track.

.form {
  display: grid;
  grid-template-columns:
    minmax(8rem, max-content)
    minmax(0, 1fr);
  gap: 1rem;
}

Simple horizontal field groups can still use Flexbox, and a vertical form stack may need neither complex model. Choose Grid when alignment across separate rows is part of the design. Keep semantic label and control associations in the HTML regardless of visual placement.

Grid for Page Shells and Dashboards

Page shells frequently coordinate headers, sidebars, main content, and supplementary panels. Grid can describe these regions as tracks or named areas and change their arrangement at content-driven breakpoints.

.page-shell {
  min-height: 100dvh;
  display: grid;
  grid-template-columns:
    16rem minmax(0, 1fr);
  grid-template-rows:
    auto minmax(0, 1fr);
  grid-template-areas:
    "header header"
    "sidebar main";
}

A flex column containing a header and a nested flex row can reproduce this basic appearance. Grid becomes clearer when regions span, align across both axes, or rearrange together because the complete structural relationship remains visible in one container.

Sidebar and Main Content Can Use Either

A simple sidebar and main region form one horizontal row, so both systems are valid. Flexbox can give the sidebar a fixed basis and let the main item grow. Grid can define a fixed or ranged sidebar track followed by a flexible main track.

.layout-flex {
  display: flex;
}

.layout-grid {
  display: grid;
  grid-template-columns:
    minmax(14rem, 18rem)
    minmax(0, 1fr);
}

Prefer Flexbox if the relationship remains one row of two items and item sizing feels natural. Prefer Grid if more rows, shared column alignment, named regions, or structural rearrangement are likely. Readability and future requirements can break the tie.

Grid Outside and Flexbox Inside

A common pattern uses Grid for a card collection and Flexbox inside each card. Grid aligns cards across the page. A column flex container then lets the card body grow and pushes actions to the bottom.

.cards {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(16rem, 1fr));
}

.card {
  display: flex;
  flex-direction: column;
}

.card__actions {
  margin-block-start: auto;
}

This is not redundant. Each system handles a different layer: Grid controls relationships among cards, while Flexbox controls the vertical relationship among elements inside one card.

Named Areas and Explicit Placement

Grid can name structural areas or place items at selected line positions. This is useful when regions form a recognizable two-dimensional map. Flexbox has no direct equivalent to a named area spanning rows and columns.

.article-layout {
  display: grid;
  grid-template-areas:
    "title title"
    "content aside";
  grid-template-columns:
    minmax(0, 1fr) 16rem;
}

Do not manually position every repeated item when Grid auto-placement already matches the intended sequence. Explicit placement is most valuable for meaningful structural regions and exceptional spans, not for reproducing ordinary list order.

Responsive Flexbox Pattern

Flexbox can create responsive field or card rows by combining wrapping with a flexible basis. Items start around a preferred size, grow to use free space, and move to a new line when necessary.

.fields {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
}

.field {
  flex: 1 1 15rem;
}

This is effective when each line may resolve independently. It is also useful when content-sized differences are desirable. If labels and inputs must align into shared columns across multiple rows, Grid communicates that requirement better.

Responsive Grid Pattern

Grid's responsive repeated-track pattern keeps a shared column structure while adapting the number of columns to the container.

.fields {
  display: grid;
  grid-template-columns: repeat(
    auto-fit,
    minmax(min(100%, 15rem), 1fr)
  );
  gap: 1rem;
}

Both examples respond without a viewport media query, but their final rows behave differently. Choose the flex version for independent lines and the grid version for shared tracks. Responsive syntax alone does not make the systems interchangeable.

Intrinsic Sizes and Overflow

Neither layout model automatically prevents overflow. Flex items have automatic minimum sizes that may stop them from shrinking. Grid tracks such as bare 1fr can also honor intrinsic minimum contributions. Wide images, tables, code blocks, or unbreakable strings can exceed a container.

.flex-child,
.grid-child {
  min-width: 0;
}

.grid-layout {
  grid-template-columns:
    minmax(0, 1fr) minmax(0, 1fr);
}

Use wrapping, responsive media, or intentional scrolling for the content itself. A correct choice between Flexbox and Grid does not remove the need to manage intrinsic dimensions and overflow.

Source Order and Visual Reordering

Flexbox provides order, while Grid supports order and explicit placement. These features can move an item visually without changing the DOM. Screen readers and keyboard focus generally continue to follow source order, creating a mismatch between what users see and what they encounter.

Keep meaningful and interactive content in a logical source sequence. Use visual reordering only when it does not alter understanding or task flow. If responsive designs require radically different reading orders, reconsider the markup and component structure instead of treating visual placement as a complete accessibility solution.

Spacing with gap

Both Grid and Flexbox support gap, which creates consistent space between layout items without adding margins to outer edges. Grid can set separate row and column gaps, while Flexbox applies gaps between items and wrapped lines.

.layout {
  gap: 1rem 1.5rem;
}

The presence of gap is no longer a reason to choose one model. Select the model based on alignment and sizing relationships. Remember that gaps consume available space and can influence wrapping or fraction calculations.

Real-World Dashboard Architecture

A dashboard demonstrates how the systems cooperate. The application shell can use Grid for sidebar and main tracks. The header toolbar can use Flexbox for controls. A metrics region can use responsive Grid tracks, while each metric card can use column Flexbox to position metadata and actions.

.dashboard {
  display: grid;
  grid-template-columns:
    16rem minmax(0, 1fr);
}

.toolbar {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.metrics {
  display: grid;
  grid-template-columns:
    repeat(auto-fit, minmax(12rem, 1fr));
}

Each container answers its own layout question. There is no need to force a single technology through every nesting level.

Real-World E-Commerce Architecture

An online shop may use Grid for filter and product regions, another Grid for the product collection, and Flexbox for price rows and card actions. On narrow containers, the outer grid can collapse to one column while internal action relationships remain one-dimensional.

.shop {
  display: grid;
  grid-template-columns:
    16rem minmax(0, 1fr);
  gap: 2rem;
}

.product__actions {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

This layered design remains understandable because every container uses the model that matches its local relationship rather than the page's overall choice.

Real-World Documentation Architecture

A documentation page may have navigation, a bounded article, and an on-page outline. Grid can maintain those three columns. The navigation itself can be a column flex container, and article callout headers can use row Flexbox.

.docs {
  display: grid;
  grid-template-columns:
    16rem
    minmax(0, 65ch)
    minmax(10rem, 14rem);
  gap: 2rem;
}

.docs-nav {
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

At narrower widths, the outline or sidebar may move, collapse, or disappear behind an explicit control. The structural breakpoint belongs to the outer Grid; the internal navigation alignment remains a Flexbox concern.

Performance and Maintainability

For ordinary interfaces, performance is rarely a sound reason to choose Flexbox over Grid or Grid over Flexbox. Modern browsers optimize both. Layout complexity, DOM size, frequent measurement, and broad style invalidation usually matter more than the difference between these two correct models.

Maintainability is more important. A simple flex row is clearer than a grid with a manually declared content-sized column for every button. A card collection is clearer as shared Grid tracks than as percentages and special rules for the final flex line. Code that expresses the real relationship is easier to debug and change.

Common Mistakes and Better Choices

Using wrapped Flexbox for a strict card grid often creates a final line whose cards grow differently. Using Grid for a simple button row adds unnecessary track definitions. Treating Flexbox as horizontal-only ignores column layouts. Treating Grid as fixed ignores auto-fit, minmax, and auto-placement.

Another mistake is using order or explicit Grid coordinates as the primary page architecture while leaving an illogical DOM sequence. Manual placement of every repeated Grid item is also unnecessary when auto-placement already follows source order. Finally, do not assume either model makes long content, localization, zoom, or small containers safe without testing.

A Practical Decision Process

Start by asking whether the component mainly needs a row or a column. If it does, try Flexbox. If rows and columns must align together, start with Grid. Then ask whether item content should drive widths or whether a declared track structure should remain stable. Consider whether wrapped lines may size independently and whether items need to span across both axes.

After selecting a model, test the simplest implementation with realistic content. If extensive workarounds are needed, revisit the choice. Nested containers are normal: changing one inner group from Grid to Flexbox does not require rewriting the page shell.

Debugging Grid and Flexbox Layouts

Browser developer tools can overlay Grid tracks and Flexbox lines. For Flexbox, inspect the main direction, wrapping, each item's basis, grow and shrink factors, automatic minimums, and margins. For Grid, inspect explicit and implicit tracks, line positions, spans, auto-placement, and track sizing functions.

1. Identify the relationship: items or shared tracks
2. Check the container's available size
3. Inspect gaps, padding, and intrinsic minimums
4. Confirm wrapping and line behavior
5. Check item bases or grid track definitions
6. Remove unnecessary order or manual placement
7. Test long content, zoom, and narrow containers
8. Compare the result with logical source order

When the layout behaves unexpectedly, reduce it to a small case. Remove decoration and keep only the container, representative items, and sizing properties. The correct model often becomes obvious once unrelated styles are absent.

Decision Matrix

RequirementTypical ChoiceReason
Navigation barFlexboxOne content-sized row
ToolbarFlexboxControl alignment and spacing
Button groupFlexboxOne-dimensional actions
Tags or chipsFlexboxIndependent content widths
Media objectFlexboxImage beside flexible content
Card internalsFlexboxVertical component flow
Page shellGridShared rows and columns
DashboardGridTwo-dimensional regions
Card collectionGridAligned columns across rows
GalleryGridTracks and spanning
Complex formGridCross-row alignment
Sidebar and mainEitherDepends on structural complexity
Center one itemEitherBoth align efficiently

Feature Comparison

FeatureFlexboxGrid
Primary dimensionOne-dimensionalTwo-dimensional
Main abstractionItems and flex linesRows and columns
Sizing focusBasis, grow, shrinkTrack sizing
Multiple-line columnsLines are independentTracks are shared
Content-driven groupsExcellentPossible
Structural layoutsPossible with nestingExcellent
Named layout areasNoYes
Two-axis spanningNo track modelExcellent
Wrappingflex-wrapAuto-placement
Gap supportYesYes
Typical combinationComponent internalsPage and collection structure

Common Interview Questions

What is the main difference between Grid and Flexbox? Flexbox primarily manages a one-dimensional row or column, while Grid manages shared rows and columns together.

When should Flexbox be used? Use it for one-dimensional alignment, spacing, and flexible item sizing in navigation, toolbars, action groups, tags, media objects, and component internals.

When should Grid be used? Use it when a track structure, cross-row column alignment, area placement, or two-axis spanning matters.

Is Grid better than Flexbox? No. They model different relationships and commonly appear together.

Why is Grid often better for card collections? Its rows share column tracks, while wrapped flex lines size independently.

Why is Flexbox often better for navigation? Navigation is usually one content-driven sequence whose items have different natural widths.

Can Flexbox create multiple rows? Yes, with wrapping, but those rows remain independent flex lines rather than one shared two-dimensional track system.

Can Grid be used for one row? Yes, but Flexbox may express a simple row of naturally sized items more clearly.

Practical Review Checklist

  • Choose Flexbox for a primary row or column relationship.
  • Choose Grid when rows and columns must align together.
  • Use Flexbox for content-sized navigation, controls, tags, and media objects.
  • Use Grid for page shells, dashboards, galleries, forms, and card collections.
  • Remember that wrapped flex lines calculate space independently.
  • Remember that Grid items align through shared tracks.
  • Combine Grid outside and Flexbox inside when each solves a different layer.
  • Keep source, reading, and keyboard order logical.
  • Avoid manual Grid placement when auto-placement is sufficient.
  • Manage intrinsic sizes and overflow in both systems.
  • Test localization, zoom, dynamic content, and narrow component containers.
  • Use developer tools to inspect flex lines and grid tracks.
  • Prefer the simplest model that accurately describes the relationship.

Key Takeaway

The most useful decision rule is to ask whether the component mainly arranges items along one direction or defines a shared structure across two directions. Flexbox arranges and sizes items within a row or column. Grid defines rows and columns, sizes those tracks, and places items within them.

Use Grid for two-dimensional page structure and repeated aligned collections. Use Flexbox for one-dimensional relationships inside headers, cards, navigation, and action groups. Neither replaces the other, and neither should be selected by habit. A well-designed interface uses each where its mental model makes the layout easiest to understand, test, and maintain.