Use CSS Container Queries for Component-Level Responsive Design

CSS Container Queries (officially the CSS Containment Module Level 3) allow a component to change its own layout based on the size of its containing element rather than the viewport width — solving the core limitation of media queries where a sidebar card and a main-content card must share the same breakpoints even though they live in containers of very different widths. A container query is enabled in two steps: first, the parent element declares itself as a containment context with container-type: inline-size (or container-type: size for both axes), and optionally a container-name to allow targeting by name; second, child styles use @container (min-width: 400px) { ... } instead of @media, and the browser evaluates the rule against the named container’s width rather than the viewport. The practical result is that a WordPress post card component can lay out its image above its text when constrained to a narrow sidebar column, and switch to a side-by-side image-text layout when placed in the wide main content grid — with zero JavaScript and no awareness of its position in the page. Container units (cqi, cqb, cqw, cqh — analogous to vi, vw, etc.) express lengths as a percentage of the container’s dimensions, enabling typography and spacing that scales relative to the component container rather than the viewport. Style Container Queries (a newer addition using container-type: style) allow querying a container’s CSS custom property values — a theme can expose a --layout variable on a section container, and child components adapt based on whether it is set to grid or list. Browser support for size-based container queries reached full coverage in all evergreen browsers in early 2023 (Chrome 105, Firefox 110, Safari 16). The CSS Grid post defines the outer layout structure; container queries handle the responsive behavior of each component within those layout regions.

Problem: A WordPress theme’s post card component is used in three contexts — a 3-column blog grid, a narrow sidebar widget, and a full-width featured section — and each context requires a different layout. The current solution uses three separate CSS classes with duplicated markup and brittle media queries tied to viewport widths that break when the sidebar width changes.

Solution: Replace the per-context class variants with a single card component that uses @container queries to self-adapt based on its own available width — no extra markup, no media queries, and no JavaScript needed.

/* ── 1. Declare containment contexts ────────────────────────────────────── */
.post-grid,
.sidebar-widget,
.featured-section {
    container-type: inline-size;
}

/* Named container for targeted queries */
.sidebar-widget {
    container-name: sidebar;
}

/* ── 2. Base (mobile-first) card styles ─────────────────────────────────── */
.post-card {
    display: grid;
    grid-template-rows: auto 1fr auto;  /* thumbnail / body / footer */
    gap: var(--space-sm);
    background: var(--color-surface);
    border-radius: var(--radius-md);
    overflow: hidden;
}

.post-card__thumbnail { aspect-ratio: 16/9; object-fit: cover; width: 100%; }
.post-card__title     { font-size: 1rem; }
.post-card__excerpt   { font-size: 0.875rem; color: var(--color-muted); }

/* ── 3. Side-by-side layout when container ≥ 480px ─────────────────────── */
@container (min-width: 480px) {
    .post-card {
        grid-template-columns: 200px 1fr;
        grid-template-rows: auto auto auto;
    }
    .post-card__thumbnail {
        grid-row: 1 / -1;  /* span all rows in the image column */
        aspect-ratio: 1;
    }
    .post-card__title   { font-size: 1.125rem; }
}

/* ── 4. Compact layout when inside the named sidebar container ───────────── */
@container sidebar (max-width: 300px) {
    .post-card {
        grid-template-columns: 80px 1fr;
        gap: var(--space-xs);
    }
    .post-card__thumbnail { aspect-ratio: 1; }
    .post-card__excerpt   { display: none; }  /* hide excerpt in tight space */
}

/* ── 5. Container query units: type scale relative to container width ─────── */
@container (min-width: 600px) {
    .post-card__title {
        font-size: clamp(1rem, 3cqi, 1.5rem); /* 3% of container inline size */
    }
}

NOTE: Setting container-type: inline-size on an element establishes size containment for the inline axis — the browser must know the element’s size before laying out its children, which means the container cannot size itself based on its children’s width. If a container wraps content that needs to stretch to fit its children horizontally, use container-type: style instead of inline-size, or restructure the layout so the container has an explicit or externally constrained width.