Modern CSS: Container Queries, :has(), Nesting & Subgrid

Master modern CSS capabilities: Component-scoped @container queries, the relational :has() parent selector, native CSS Nesting, Subgrid alignment, and fluid math functions.

1. Real-World Analogy: Modular Smart Furniture vs Room Architecture

Modern CSS transitions web design from rigid page-level blueprints to modular, self-aware UI components:

📦 Container Queries (`@container`)

Like expandable modular furniture. If you put a sofa in a narrow studio apartment room (sidebar), it folds into an armchair. If you place the exact same sofa in a spacious lounge (main feed), it expands into a sectional — regardless of the total building footprint (viewport)!

🔍 The Relational Selector (`:has()`)

Like a smart airport luggage scanner. Instead of inspecting each bag separately, the conveyor belt machine triggers a red warning light on the outer suitcase if and only if it detects battery electronics inside.

🌿 Native CSS Nesting (`&`)

Like nested organizational folders in your OS. Child styles reside right inside their parent block without requiring third-party build tools (Sass/Less) or duplicated class prefixes.

2. Container Queries (`@container` & Units)

While Media Queries respond to the entire viewport width, Container Queries allow a component to style itself dynamically based on the width of its immediate container element.

/* Step 1: Designate the parent element as a queryable container context */
.card-wrapper {
    container-type: inline-size; /* Measures container's inline (width) axis */
    container-name: card-container; /* Optional named container */
}

/* Step 2: Query the container's width, NOT the window viewport */
@container card-container (min-width: 480px) {
    .product-card {
        display: grid;
        grid-template-columns: 180px 1fr;
        gap: 1.5rem;
    }
    
    .product-card__title {
        font-size: 1.5rem;
    }
}

/* Step 3: Container Query Units (cqw = 1% of container width) */
.product-card__badge {
    font-size: clamp(0.75rem, 3cqw, 1.25rem);
}

Container Query Units Overview

Unit Description Viewport Equivalent
cqw 1% of query container's width (inline size) vw (1% viewport width)
cqh 1% of query container's height (block size) vh (1% viewport height)
cqi 1% of query container's inline size vi
cqmin / cqmax Smaller or larger value between cqi and cqb vmin / vmax

3. The Relational Parent Selector: :has()

The :has() pseudo-class represents an element if any of the relative selectors passed into it match at least one element. It unlocks the long-awaited "parent selector" and conditional sibling styling in pure CSS:

/* 1. Style parent card if it contains a featured badge child */
.article-card:has(.badge--featured) {
    border: 2px solid #6C4CE8;
    background: #F5F3FF;
}

/* 2. Highlight form wrapper when ANY child input is invalid & touched */
form:has(input:invalid:user-valid) {
    border-left: 4px solid #EF4444;
}

/* 3. Darken body and lock scrolling when modal dialog is open */
body:has(dialog[open]) {
    overflow: hidden;
}

/* 4. Sibling hover focus effect: dim siblings when one is hovered */
.menu-list:has(li:hover) li:not(:hover) {
    opacity: 0.4;
    filter: blur(1px);
    transition: opacity 0.2s ease;
}

4. Native CSS Nesting

CSS now natively supports selector nesting without needing preprocessors like Sass or Less. The nesting selector & explicitly references the parent selector:

.card {
    background: #FFFFFF;
    padding: 1.5rem;
    border-radius: 8px;

    /* Direct element nesting */
    h3 {
        color: #0F172A;
        font-size: 1.25rem;
    }

    /* Pseudo-class targeting parent with & */
    &:hover {
        box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1);
    }

    /* Class modifier on parent */
    &.card--dark {
        background: #1E293B;
        color: #FFFFFF;
    }

    /* Nested Media Query inside the component */
    @media (max-width: 640px) {
        padding: 1rem;
    }
}

5. CSS Subgrid & Fluid Math Functions

Subgrid allows nested child grids to participate directly in the parent grid's row and column tracks, ensuring cards in different containers have identical header and footer heights.

/* 1. Subgrid alignment across sibling cards */
.grid-container {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    grid-auto-rows: auto 1fr auto; /* header, body, footer */
    gap: 1.5rem;
}

.grid-container > .card {
    display: grid;
    grid-row: span 3; /* Spans 3 tracks of the parent */
    grid-template-rows: subgrid; /* Inherits parent's row alignments! */
}

/* 2. Fluid Typography with clamp() */
h1 {
    /* clamp(MIN, PREFERRED, MAX) */
    font-size: clamp(1.75rem, 4vw + 1rem, 3.5rem);
}

6. Interactive Workbench: Live Modern CSS Playground

Resize the simulated parent container using the range slider and toggle the checkbox to see @container queries and the :has() parent selector react in real-time!

/* Live Container & :has() Engine */
.demo-card-wrapper {
    container-type: inline-size;
    container-name: demoBox;
}

/* When container >= 380px -> Horizontal flex */
@container demoBox (min-width: 380px) {
    .modern-widget {
        flex-direction: row;
        align-items: center;
    }
}

/* :has() parent styling */
.modern-widget:has(input[type="checkbox"]:checked) {
    border: 2px solid #10B981;
    background: #ECFDF5;
}
🚀

Container-Aware Card

Layout flexes automatically based on container width!

🎯 Modern CSS Interview Quiz
Score: 0 / 5 Question 1 of 5
Container Queries

Which CSS property must be applied to a parent element so its descendants can query its width using @container?

A) container-mode: auto;
B) container-type: inline-size;
C) query-context: container;
D) display: container-grid;
Relational Selector :has()

What element does the selector article:has(h2 + p) target?

A) The <p> element directly following the <h2> inside an article
B) The <h2> element that precedes a <p>
C) The <article> element itself if it contains an <h2> immediately followed by a <p>
D) All elements inside the article except <h2> and <p>
Container Query Units

If a parent container has an inline width of 400px, what computed pixel value does 10cqw resolve to?

A) 40px
B) 4px
C) 10px
D) 400px
CSS Subgrid

Which CSS declaration enables a nested child grid to directly align its rows with the parent grid's tracks?

A) grid-rows: inherit;
B) display: subgrid-flex;
C) grid-template-rows: auto-parent;
D) grid-template-rows: subgrid;
Selector Constraints & Traps

Which of the following selector expressions is INVALID according to the CSS specification?

A) form:has(> button:disabled)
B) div:has(:has(p)) (Nested :has())
C) li:has(+ li:hover)
D) section:not(:has(h2))

🎯 Placement Interview Key Takeaways & Common Traps

  • Trap 1: Forgetting container-type — An element cannot respond to @container rules unless an ancestor has container-type: inline-size or container-type: size declared.
  • Trap 2: Can a container query itself? — No! An element cannot query its own dimensions with @container. Container queries can only style descendants of the container to prevent infinite layout circularity.
  • Trap 3: Specificity of Nesting with & — In CSS Nesting, & is parsed similarly to :is(). The specificity of :is() is determined by the most specific selector in its arguments list.
  • Trap 4: Disallowed :has() Nesting — You cannot nest :has() inside another :has() (e.g. div:has(:has(p)) is explicitly forbidden by the CSS specification to avoid pathological performance trees).