DevToolBoxFREE
Blog

CSS Grid Mastery: Complete Guide with Real-World Examples 2026

14 min readby DevToolBox

CSS Grid is the most powerful layout system ever added to CSS. While Flexbox handles one-dimensional layouts (rows OR columns), Grid handles two-dimensional layouts (rows AND columns simultaneously). In 2026, Grid Level 2 features like subgrid are fully supported across all major browsers, unlocking alignment patterns previously impossible in CSS.

Grid Basics: Columns, Rows, and Placement

Grid creates a two-dimensional coordinate system. Items are placed by specifying their position in the grid using line numbers, span values, or named areas.

/* CSS Grid fundamentals */
.grid-container {
    display: grid;

    /* Define columns */
    grid-template-columns: 200px 1fr 1fr;        /* fixed + flexible */
    grid-template-columns: repeat(3, 1fr);        /* 3 equal columns */
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); /* responsive */

    /* Define rows */
    grid-template-rows: auto 1fr auto;            /* header, content, footer */

    /* Gaps */
    gap: 1rem;            /* both row and column gap */
    row-gap: 0.5rem;
    column-gap: 1.5rem;

    /* Alignment */
    justify-items: stretch;   /* horizontal alignment of cells */
    align-items: start;       /* vertical alignment of cells */
    justify-content: center;  /* horizontal alignment of the grid */
    align-content: center;    /* vertical alignment of the grid */
}

/* Place items */
.item {
    grid-column: 1 / 3;      /* span from column 1 to 3 */
    grid-row: 1 / 2;
    grid-column: span 2;      /* span 2 columns */
    grid-area: 1 / 1 / 3 / 3; /* row-start / col-start / row-end / col-end */
}

grid-template-areas: Visual Layout Definition

grid-template-areas lets you define the layout visually using ASCII art. Each string represents a row; repeated names create spanning areas. A dot (.) creates an empty cell.

/* grid-template-areas: name regions visually */
.page-layout {
    display: grid;
    grid-template-areas:
        "header  header  header"
        "sidebar main    main"
        "sidebar aside   aside"
        "footer  footer  footer";
    grid-template-columns: 250px 1fr 300px;
    grid-template-rows: 60px 1fr auto 80px;
    min-height: 100vh;
    gap: 1rem;
}

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

/* Responsive: stack on mobile */
@media (max-width: 768px) {
    .page-layout {
        grid-template-areas:
            "header"
            "main"
            "aside"
            "sidebar"
            "footer";
        grid-template-columns: 1fr;
        grid-template-rows: auto;
    }
}

auto-fill vs auto-fit: Responsive Without Media Queries

auto-fill and auto-fit with minmax() create responsive grids without any media queries. The difference: auto-fill preserves empty tracks; auto-fit collapses them.

/* auto-fill vs auto-fit — the most important Grid distinction */

/* auto-fill: creates as many columns as possible, even if empty */
.gallery-fill {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1rem;
}
/* Result: always fills the row with tracks, even with empty ones */

/* auto-fit: collapses empty tracks, stretches filled items */
.gallery-fit {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: 1rem;
}
/* Result: items expand to fill available space */

/* Practical: responsive card grid (no media queries!) */
.card-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(300px, 100%), 1fr));
    gap: 1.5rem;
}
/* min(300px, 100%) prevents overflow on very small screens */

minmax() and Intrinsic Sizing

minmax(min, max) sets the minimum and maximum size of a grid track. Combined with auto-fill and min(), it creates layouts that adapt naturally to any content and viewport.

/* minmax() — set minimum and maximum track size */

/* Card layout: minimum 250px, maximum 1fr */
.cards {
    display: grid;
    grid-template-columns: repeat(3, minmax(250px, 1fr));
}

/* Intrinsic sizing with min-content / max-content */
.table-grid {
    display: grid;
    grid-template-columns: max-content 1fr max-content;
    /* First and last columns size to content, middle fills rest */
}

/* fit-content() — like minmax(auto, max-content) but capped */
.nav {
    display: grid;
    grid-template-columns: fit-content(200px) 1fr fit-content(200px);
}

/* Dense packing: fill holes left by spanning items */
.masonry-like {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    grid-auto-rows: 150px;
    grid-auto-flow: dense; /* fills gaps automatically */
}

.tall-item {
    grid-row: span 2; /* takes 2 rows */
}
.wide-item {
    grid-column: span 2; /* takes 2 columns */
}

Subgrid: CSS Grid Level 2 (2026)

Subgrid allows a nested grid to participate in the parent grid's track definition. This solves the "card alignment" problem where content inside separate cards couldn't align across cards.

/* Subgrid — CSS Grid Level 2, fully supported in 2026 */
/* Allows nested grids to align to parent grid lines */

/* The problem subgrid solves: */
.card-container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 1rem;
}

/* Without subgrid: each card's internal layout is independent */
/* Card titles and content don't align across cards */

/* With subgrid: */
.card {
    display: grid;
    grid-row: span 3; /* card spans 3 implicit rows */
    grid-template-rows: subgrid; /* inherits parent row tracks */
}
/* Now all cards share the same row grid — titles align! */

.card .card-header { grid-row: 1; }
.card .card-body   { grid-row: 2; }
.card .card-footer { grid-row: 3; }

/* Subgrid for columns too */
.sidebar-layout {
    display: grid;
    grid-template-columns: 1fr 3fr;
}

.main-content {
    display: grid;
    grid-column: 2;
    grid-template-columns: subgrid; /* aligns to parent columns */
}

/* Browser support: Chrome 117+, Firefox 71+, Safari 16+ — all major browsers */

Grid Animations and Transitions

Modern browsers support transitioning grid-template-columns and grid-template-rows. This enables smooth sidebar expansions and CSS-only accordion animations.

/* Grid transitions and animation */

/* Animate grid column width on hover */
.sidebar-layout {
    display: grid;
    grid-template-columns: 250px 1fr;
    transition: grid-template-columns 0.3s ease;
}

.sidebar-layout:has(.sidebar:hover) {
    grid-template-columns: 350px 1fr; /* expand on hover */
}

/* CSS-only accordion with Grid */
.accordion-item {
    display: grid;
    grid-template-rows: auto 0fr; /* collapsed: 0 fraction */
    transition: grid-template-rows 0.3s ease;
    overflow: hidden;
}

.accordion-item.open {
    grid-template-rows: auto 1fr; /* expanded: 1 fraction */
}

.accordion-content {
    min-height: 0; /* required for 0fr to work */
}

CSS Grid vs Flexbox: When to Use Which

ScenarioCSS GridFlexbox
Page layout (header/footer/sidebar)PerfectAwkward
Navigation bar itemsWorksPerfect
Card grid (equal columns)PerfectNeeds JS for equal height
Centering contentEasy (place-items)Easy (align/justify)
Vertical list of itemsWorksPerfect
Complex form layoutPerfectComplex
Responsive without breakpointsauto-fill/fitLimited

Best Practices

  • Use Grid for page-level layouts (header/sidebar/main/footer). Use Flexbox for component-level layouts (navigation items, button groups, card content).
  • Prefer repeat(auto-fill, minmax()) over fixed column counts for responsive card grids — eliminates most breakpoints.
  • Name your grid areas with grid-template-areas for complex layouts. Names serve as self-documenting CSS.
  • Use subgrid whenever you need items in separate grid children to align — card footers, table cells, price rows.
  • gap is now universally supported (replacing grid-gap). Use it instead of margins for grid spacing.

Frequently Asked Questions

When should I use CSS Grid vs Flexbox?

CSS Grid excels at two-dimensional layouts where you control both rows and columns. Flexbox is better for one-dimensional layouts: a row of navigation links, a vertical stack of items, or content within a card. Many designs use Grid for the macro layout and Flexbox for components within grid cells.

What is the difference between grid-template-columns and grid-auto-columns?

grid-template-columns defines explicit columns you specify upfront. grid-auto-columns sets the size of implicitly created columns (when items overflow the defined grid). Similarly, grid-template-rows vs grid-auto-rows handles explicit vs implicit rows.

How does subgrid differ from nested grid?

A nested grid creates its own independent grid coordinate system. Subgrid inherits the parent's track definitions, so child items align to the parent grid's lines. This is crucial for multi-column card layouts where titles, content, and footers need to align across separate cards.

What does grid-auto-flow: dense do?

By default, Grid places items in order, leaving holes when a large item can't fit. grid-auto-flow: dense makes the browser try to fill those holes with later items. This is useful for image galleries with items of varying sizes, creating a tighter masonry-like layout.

Can I mix Grid and Flexbox?

Absolutely. Grid and Flexbox work at different levels. A typical pattern: CSS Grid for the page layout (header, sidebar, main), Flexbox for the header navigation (logo + links + CTA), and Grid again for a card section inside main. Mixing them is normal and encouraged.

Related Tools

𝕏 Twitterin LinkedIn
Was this helpful?

Stay Updated

Get weekly dev tips and new tool announcements.

No spam. Unsubscribe anytime.

Try These Related Tools

🌈CSS Gradient GeneratorCSS Triangle Generator🎨Color Picker Online

Related Articles

Tailwind CSS Component Patterns: Building Reusable UI with Utility Classes in 2026

Advanced Tailwind CSS component patterns in 2026: design tokens, compound components, polymorphic components, and building a consistent design system without CSS-in-JS.

React Query Patterns 2026: Data Fetching, Caching, and Mutations with TanStack Query

Master React Query (TanStack Query) patterns in 2026: useQuery, useMutation, optimistic updates, infinite queries, and server state management.