CSS container queries explained with practical WordPress examples

CSS container queries are a major evolution in responsive design that landed in all major browsers in 2023. They let you apply styles to an element based on the size of its parent container rather than the size of the viewport — which is exactly what component-based design has always needed. Media queries answer the question “how wide is the browser window?”; container queries answer “how wide is the box this component lives in?”. This distinction matters enormously for reusable WordPress components: a card component used in a full-width hero should look different from the same card in a narrow sidebar — and with media queries you cannot make this distinction without separate classes or JavaScript. With container queries, you define a containment context on the parent with container-type: inline-size (or the shorthand container property), then write @container rules on the child elements. You can also name containers with container-name and target named containers specifically with @container name (min-width: 400px). The cqi (container inline percentage) and cqw (container width) units let you size elements relative to their container, just like vw does for the viewport. Browser support is now universal in modern browsers (Chrome 105+, Firefox 110+, Safari 16+) with no polyfill needed for new WordPress projects targeting modern browsers. Combine container queries with CSS Grid and CSS custom properties for a fully modern WordPress theme architecture.

Problem: A reusable WordPress card component needs to adapt its layout based on the width of its container (sidebar vs. main content area), not the viewport width.

Solution: Add the following CSS to your theme stylesheet:

/* ── Define a containment context on the parent ────────────────────────────── */
.card-wrapper {
    container-type: inline-size; /* enable width-based container queries */
    container-name: card;        /* optional: name for targeting */
}

/* ── Default card styles (narrow — stacked layout) ─────────────────────────── */
.card {
    display: grid;
    grid-template-rows: auto 1fr;
    gap: 12px;
    padding: 16px;
    background: #fff;
    border-radius: 8px;
}

.card__image { width: 100%; aspect-ratio: 16/9; object-fit: cover; border-radius: 4px; }
.card__title { font-size: 1rem; font-weight: 600; }
.card__excerpt { font-size: 0.875rem; color: #555; }

/* ── Container query: side-by-side layout when container >= 480px ──────────── */
@container card (min-width: 480px) {
    .card {
        grid-template-columns: 200px 1fr;
        grid-template-rows: auto;
        align-items: start;
    }
    .card__image {
        width: 200px;
        aspect-ratio: 1;
        grid-row: 1 / 3;
    }
    .card__title { font-size: 1.125rem; }
}

/* ── Container query: large card with featured layout >= 700px ─────────────── */
@container card (min-width: 700px) {
    .card {
        grid-template-columns: 1fr;
        grid-template-rows: auto auto auto;
    }
    .card__image {
        width: 100%;
        aspect-ratio: 21/9;
        grid-row: auto;
    }
    .card__title { font-size: 1.5rem; }
}

/* ── Container query units: title font scales with container width ──────────── */
@container (min-width: 300px) {
    .card__title {
        font-size: clamp(1rem, 3cqi, 1.5rem); /* cqi = container inline percentage */
    }
}

/* ── Named container: target a specific ancestor ───────────────────────────── */
.sidebar { container: sidebar / inline-size; }

@container sidebar (max-width: 280px) {
    .card__excerpt { display: none; } /* hide excerpt in very narrow sidebars */
}

NOTE: You cannot apply a container query to the same element that defines the containment context — @container rules apply to descendants of the container, not the container element itself. This is by design: the container establishes a size-query boundary for its children. Also, container-type: inline-size only enables querying the inline dimension (width in horizontal writing modes); use container-type: size if you also need to query height, but this requires the element to have an explicitly defined height, which is rarely practical for content boxes.