CSS Grid layout guide with WordPress block theme examples

CSS Grid is the most powerful layout system available in CSS, and it is now the backbone of WordPress block themes. The block editor’s columns block, the query loop grid view, and the theme.json layout settings all rely on CSS Grid under the hood. Understanding Grid directly lets you extend and override these defaults, build custom post-grid templates, and create complex magazine-style layouts that would have required JavaScript or nested table hacks in the past. Grid works on two dimensions simultaneously — rows and columns — unlike Flexbox which is primarily one-dimensional. You define a grid container with display: grid and then describe the column and row structure with grid-template-columns and grid-template-rows. The repeat() function, the fr fractional unit, and the minmax() function together make it possible to write responsive grids that adapt to any screen width without a single media query. repeat(auto-fill, minmax(280px, 1fr)) is the canonical responsive card grid: it creates as many columns as will fit at the minimum width, and each column stretches equally to fill the available space. Grid items can span multiple columns and rows with grid-column and grid-row shorthand, enabling a featured-post slot that takes up twice the space of regular cards. Named grid template areas with grid-template-areas provide a visual ASCII map of your layout directly in CSS, making complex layouts easy to read and maintain. The clip-path guide shows how to add shaped sections on top of Grid-based layouts. Pair this with the block theme guide for a complete FSE workflow.

Problem: You need to build responsive post-card grids, magazine-style featured layouts, and full-page block-theme templates in CSS without relying on floats, a CSS framework, or multiple media queries.

Solution: Use CSS Grid with repeat(), minmax(), fr, and grid-template-areas for fully responsive, zero-media-query layouts:

/* Responsive card grid — auto-fill columns, min 280px each */
.post-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
    gap: 2rem;
}

/* Magazine layout — featured post spans 2 columns + 2 rows */
.magazine-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-template-rows: auto auto;
    gap: 1.5rem;
}
.magazine-grid .post-featured {
    grid-column: 1 / 3;
    grid-row:    1 / 3;
}

/* Named areas layout for a page template */
.page-layout {
    display: grid;
    grid-template-columns: 1fr 300px;
    grid-template-rows: auto 1fr auto;
    grid-template-areas:
        "header  header"
        "content sidebar"
        "footer  footer";
    min-height: 100vh;
    gap: 0 2rem;
}
.site-header  { grid-area: header;  }
.site-content { grid-area: content; }
.site-sidebar { grid-area: sidebar; }
.site-footer  { grid-area: footer;  }

/* Stack to single column on narrow screens */
@media (max-width: 768px) {
    .page-layout {
        grid-template-columns: 1fr;
        grid-template-areas:
            "header"
            "content"
            "sidebar"
            "footer";
    }
}

/* Fluid typography grid item — clamp() for responsive font size */
.card-title {
    font-size: clamp(1rem, 2.5vw, 1.5rem);
}

NOTE: In WordPress block themes, the query loop block generates a .wp-block-query container — you can override its grid by targeting it in style.css or in theme.json under settings.layout. When placing a Grid layout inside a block template, wrap it in a block to respect the theme’s content width. The gap property replaces the old grid-gap alias and is supported in all modern browsers — use it instead of margins on grid items to maintain even spacing without the last-item margin hack.